home *** CD-ROM | disk | FTP | other *** search
/ Aminet 4 / Aminet 4 - November 1994.iso / aminet / comm / misc / avmnfaxsrc1_33.lha / efax0.6a.c < prev    next >
C/C++ Source or Header  |  1994-06-03  |  66KB  |  2,163 lines

  1. #define Copyright         "Copyright 1994  Ed Casas"
  2.  
  3. #define Version          "efax v 0.6a"
  4.  
  5. /*
  6.     Copyright (C) 1994  Ed Casas
  7.  
  8.     This program is free software; you can redistribute it and/or modify
  9.     it under the terms of the GNU General Public License as published by
  10.     the Free Software Foundation; either version 2 of the License, or
  11.     (at your option) any later version.
  12.  
  13.     This program is distributed in the hope that it will be useful,
  14.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.     GNU General Public License for more details.
  17.  
  18.     You should have received a copy of the GNU General Public License
  19.     along with this program; if not, write to the Free Software
  20.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22.     You may contact the author by e-mail at: edc@ee.ubc.ca,
  23.     or by mail at: 2629 West 3rd Ave, Vancouver, BC, Canada,
  24.     V6K 1M4.
  25.  
  26. */
  27.  
  28. const char *Usage =
  29.   "Usage:\n"
  30.   "  %s [ option ]... [ -r pat | -t num file... ]\n"
  31. "Options:\n"
  32.   "  -c cap  set file format or receive capabilites to cap\n"
  33.   "  -d dev  use modem on device dev\n"
  34.   "  -g cmd  exec \"/bin/sh -c cmd\" for data calls\n"
  35.   "  -i str  send modem command ATstr at start\n"
  36.   "  -l id   set local indetification to id\n"
  37.   "  -o opt  use protocol option opt:\n"
  38.   "      1     use class 1 modem commands\n"
  39.   "      a     if first [data mode] answer attempt fails retry as fax\n"
  40.   "      e     ignore errors in modem initialization commands\n"
  41.   "      r     reverse bit order on receive\n"  
  42.   "      x     use XON instead of DC2 to trigger reception\n"
  43.   "      z     add 100 ms to pause before each modem comand (cumulative)\n"
  44.   "  -q ne   ask for retransmission if more than ne errors per page\n"
  45.   "  -s      share (unlock) modem device while waiting for call\n"
  46.   "  -v lvl  print messages of type in string lvl (ewinchamr)\n"
  47.   "  -w      don't answer phone, wait for OK or CONNECT instead\n"
  48.   "  -x fil  use uucp-style lock file fil\n"
  49.   "  -z str  send modem command ATstr when done\n"
  50.   "Commands:\n"
  51.   "  -r      answer and receive fax into files pat.001, pat.002, ... \n"
  52.   "  -t      send fax image files file... to telephone num\n"
  53.   ;
  54.  
  55. #include <ctype.h>        /* ANSI C */
  56. #include <errno.h>
  57. #include <signal.h>    
  58. #include <stdarg.h> 
  59. #include <stdio.h>
  60. #include <stdlib.h>
  61. #include <string.h>
  62. #include <time.h>
  63.  
  64. #include <fcntl.h>        /* POSIX */
  65. #include <unistd.h>
  66. #include <sys/types.h>
  67.  
  68. #include <sys/time.h>        /* select() */
  69.  
  70. #ifndef FD_SET
  71. #include <select.h>        /* for AIX */
  72. #endif
  73.  
  74. #include <sys/stat.h>        /* for SysV (?) */
  75.  
  76. #ifdef TERMIO
  77. #include <termio.h>
  78. #include <sys/ioctl.h>
  79. #define termios termio
  80. #define tcgetattr(fd, pt) ioctl(fd, TCGETA, pt)
  81. #define tcsetattr(fd, x, pt) ioctl(fd, TCSETAW, pt)
  82. #define cfsetospeed(pt, b) ((pt)->c_cflag = ((pt)->c_cflag & ~CBAUD) | b)
  83. #define cfsetispeed(pt, b)
  84. #define tcdrain(fd)
  85. #else
  86. #include <termios.h>
  87. #endif
  88.  
  89. #ifndef FILENAME_MAX
  90. #define FILENAME_MAX 255
  91. #endif
  92.  
  93. #ifndef u_char
  94. #define u_char unsigned char
  95. #endif
  96.  
  97. /* constants... */
  98.  
  99. #define FAXFILE "/dev/fax"  /* default fax modem device */
  100. #define LOGF     stderr     /* session log written to this stream */
  101.  
  102.                 /* delays/timeouts, in deciseconds */
  103. #define TO_RESET  26        /* timeout for modem reset commands (per Hayes) */
  104. #define T_CMD     1        /* pause before each modem command */
  105. #define TO_A      1200        /* dial/answer (Phase A) - modem may T.O. first */
  106.  
  107. #define TO_DATAF  150        /* software adaptive answer data connect */
  108.  
  109. #define T1 350            /* T.30 T1 - waiting for DIS/DCS before Phase B */
  110. #define T2 60            /* T.30 T2 - waiting for frame in Phase B */
  111. #define T3S 30            /* T.30 response timeout (not T3) */
  112. #define T4 30            /* T.30 T4 - between [re]transmissions of DIS */
  113.  
  114. #define TO_DRAIN 140        /* drain 4k modem buffer at 2400bps (tx) */
  115. #define TO_RTCMD 10        /* return to command mode after DLE-ETX (rx) */
  116. #define TO_FT    31        /* max delay after +F[TR][MH] command */
  117. #define TO_CHAR  51        /* per data character (max FILL length) */
  118. #define TO_ABRT  20        /* max delay after sending abort sequence */
  119.  
  120. #define TO_C2B    450        /* Class 2 DIS to CONNECT:(DCS+TCF+CFR)xretries */
  121. #define TO_C2X    20        /* Class 2 wait for XON: 2/5 of 5s timeout */
  122. #define TO_C2PP   200        /* Class 2 wait for ppr: (ppm+ppr)x3retries + 2 */
  123. #define TO_C2R    600        /* Class 2 receive: (TCF+FTT)x11 retrains + 5 */
  124. #define TO_C2EOR  60        /* Class 2 end of data rx (2 retrans x 3 s) */
  125.  
  126.  
  127. #define CMDBUFSIZE 128      /* longest possible modem command or response */
  128. #define DEFDISLEN 3        /* length of DIS initially transmitted */
  129. #define DEFCAP 1,3,0,2,0,0,0,0    /* default local capabilities */
  130. #define DLE_ETX "\020\003"  /* DLE-ETX (end of data) string */
  131. #define FNAMFT "%m%d%H%M%S" /* strftime() format for default file name */
  132. #define HDBLKFLAG '#'        /* prefix to force HDB (text) lock file style */
  133. #define IDLEN 20        /* length of T.30 identification strings */
  134. #define LOCKPOLLDELAY 15    /* seconds between checks of lock files */
  135. #define MAXDIS 8        /* maximum DIS frames sent without response (T1) */
  136. #define MAXFIFLEN 125        /* max FIF len = MAXFRLEN - (adx+ctl+FCF) - FCS */
  137. #define MAXFRLEN 130        /* max frame length = 3.45s x 300 bps / 8 */
  138. #define MAXGETTY 512        /* maximum length of ``getty'' (-g) command */
  139. #define MAXIOPT  100        /* maximum # of modem initialization commands */
  140. #define MAXLKFILE 16        /* maximum number of lock files */
  141. #define MAXMSGBUF 8192        /* maximum size of message buffer */
  142. #define MAXNULLS 2        /* maximum consecutive received nulls saved */
  143. #define MAXTSTAMP 80        /* maximum length of a time stamp */
  144. #define MAXTRAINERR 0        /* maximum errors allowed in training check data */
  145. #define MAXTRAIN 2        /* maximum training retries at lowest speed */
  146. #define MAXRETRY 3        /* maximum retries of unacknowledged commands */
  147. #define MINWRITE  128       /* minimum bytes per write() to modem */
  148. #define NCAP 8              /* number of fields in a capability string */
  149. #define NTXRETRY  3        /* maximum re-sends per page */
  150. #define RCVBUFSIZE 1024        /* read up to this many bytes at a time from fax */
  151. #define SNDBUFSIZE 1024        /* maximum bytes to write at a time to fax */
  152. #define T4RTCLEN  9        /* end of page mark for T.4 coded images */
  153. #define T4RTC    "\000\020\001\000\020\001\000\020\001"
  154.  
  155. enum  cchar {                /* control characters */
  156.   NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL, BS,  HT,  LF,
  157.   VT,  FF,  CR,  SO,  SI,  DLE, XON, DC2, XOFF,DC4, NAK,
  158.   SYN, ETB, CAN, EM,  SUB, ESC, FS,  GS,  RS,  US } ;
  159.  
  160. const char *prompts[] = {        /* modem responses that are prompts */
  161.   "OOK", "-CONNECT FAX", "CCONNECT", "NNO CARRIER", "EERROR",
  162.   "NNO DIALTONE", "BBUSY", "NNO ANSWER", "E+FCERROR", 0 } ;
  163.  
  164. enum promptcodes {            /* codes for modem prompts */
  165.    BUSY = 'B', CONNECT = 'C', OK = 'O', RING = 'R', NO = 'N',
  166.    ERROR = 'E' } ;
  167.  
  168. enum ttymodes                /* serial port modes */
  169.    { COMMAND, DROPDTR, SEND, ORIGINAL } ;
  170.  
  171.                 /* signals to be caught so can hang up phone */
  172. const int catch [] = { SIGHUP, SIGINT, SIGQUIT, SIGIOT, SIGSEGV, SIGALRM,
  173.                SIGTERM, SIGFPE, 0 } ;
  174.  
  175. typedef int cap [ NCAP ] ;        /* remote/local capabilities */
  176.  
  177.                                         /* capability fields... */
  178. enum  captype {                   VR, BR, WD, LN, DF, EC, BF, ST } ;
  179. const int capmax [ NCAP ] = {   1,  7,  3,  2,  3,  2,  1,  7 } ;
  180.                     /* & maximum values */
  181.  
  182.                     /* characters per second for br */
  183. const int cps [ 8 ] = { 300, 600, 900, 1200, 1500, 1800, 900, 1200 } ;
  184.  
  185.                     /* next br = fallback [ br ] */
  186. const int fallback [ 8 ] = { 0, 0, 1, 2, 7, 4, 3, 6 } ;
  187.  
  188.                     /* minimum scan time in ms  */
  189. const int delay [ 8 ] = { 0 , 5, 10, 10, 20, 20, 40, 40 } ;
  190.  
  191. /* Table to convert between T.30 DIS/DCS/DTC FIF and Class 2-like
  192.    capability codes. Uses br=6, 7 for V.17 at 7200, 9600. */
  193.  
  194. typedef const struct t30tabstruct
  195.   char *name ; 
  196.   u_char byte, shift, mask ; 
  197.   u_char captodis[8], distocap[16], captodcs[8], dcstocap[16] ; 
  198. } t30tabst ;
  199.  
  200. #define X 0xff                /* invalid values */
  201.  
  202. t30tabst t30tab [ NCAP ] = {
  203.   { "vr", 1, 1, 0x01, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },     
  204.   { "br", 1, 2, 0x0f, 
  205.       { 0, 4, 12, 12, 13, 13 } ,
  206.       { 0, X, X, X, 1, X, X, X, 3, X, X, X, 3, 5, 3, X } ,
  207.       { 0, 4, 12, 8, 5, 1 } ,
  208.       { 0, 5, 5, X, 1, 4, 4, X, 3, 7, X, X, 2, 6, X, X } } ,
  209.   { "wd", 2, 6, 0x03, { 0, 2, 1 } , { 0, 2, 1, 2 } ,
  210.       { 0, 2, 1 } , { 0, 2, 1, 2 } },
  211.   { "ln", 2, 4, 0x03, { 0, 2, 1 } , { 0, 2, 1, X } ,
  212.       { 0, 2, 1 } , { 0, 2, 1, X } },
  213.   { "df", 1, 0, 0x01, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
  214.   { "ec", 3, 4, 0x03, { 0, 2, 2 } , { 0, X, 2, X } , 
  215.       { 0, 3, 2 } , { 0, 0, 2, 1 } }, 
  216.   { "bf", 5, 5, 0x01, { 0, 1 } , { 0, 1 } , { 0, 1 } , { 0, 1 } },
  217.   { "st", 2, 1, 0x07, 
  218.       { 7, 4, 3, 2, 6, 0, 5, 1 } , { 5, 7, 3, 2, 1, 6, 4, 0 } ,
  219.       { 7, 4, X, 2, X, 0, X, 1 } , { 5, 7, 3, 1, X, X, X, 0 } } 
  220. } ;
  221.  
  222.                     /* values of capability fields */
  223. const char *capvaluestr [ NCAP ] [8] = {
  224.   { " 98lpi", "196lpi" } , 
  225.   { " 2400bps", " 4800bps", " 7200bps", " 9600bps", "  12kbps", "14.4kbps",
  226.     "7200bpsV.17", "9600bpsV.17" } ,
  227.   { "8.5\"/215mm", " 10\"/255mm", " 12\"/303mm" } ,
  228.   { "11\"/A4", "14\"/B4", " any  " } ,
  229.   { "1D" , "2D" }, { "   -   ", "ECM-256", "ECM-64 " }, { " - ", "BFT" },
  230.   { "0ms", "5ms", "10/5ms", "10ms", "20/10ms", "20ms", "40/20ms", "40ms" }
  231. } ;
  232.  
  233. /* T.30 control frames */
  234.  
  235. enum frametype {        
  236.  DIS=0x01, CSI,    NSF=0x04,
  237.  CFR=0x21, FTT,
  238.  MCF=0x31, RTN, RTP, PIN, PIP,
  239.  DCS=0x41, TSI,    NSS=0x44,
  240.  CRP=0x58, DCN=0x5f,
  241.  EOM=0x71, MPS, EOP=0x074, PRI_EOM=0x79, PRI_MPS, PRI_EOP=0x7c,
  242.  DTC=0x80, CIG, NSC=0x84
  243.  } ;
  244.  
  245. /* Class 1 commands to [receive=0/transmit=1] [data=0/training=1] for
  246.    [baud rate=BR]. */
  247.  
  248. const char *c1cmd [ 2 ]  [ 2 ] [ 8 ] = { 
  249. { { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=122", "+FRM=146" ,
  250.     "+FRM=74", "+FRM=98" } ,
  251.   { "+FRM=24", "+FRM=48", "+FRM=72", "+FRM=96", "+FRM=121", "+FRM=145" ,
  252.     "+FRM=73", "+FRM=97" } } ,
  253. { { "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=122", "+FTM=146" ,
  254.     "+FTM=74", "+FTM=98", } ,
  255.   { "+FTM=24", "+FTM=48", "+FTM=72", "+FTM=96", "+FTM=121", "+FTM=145" ,
  256.     "+FTM=73", "+FTM=97" } }
  257. } ;
  258.  
  259.  
  260. /* World's fastest T.4 decoder.  Implements a tree search.  Each bit of
  261.    each byte is tested using the T4TST(byte,bitmask) macro. This macro
  262.    invokes the macro T4CODE(len) when it detects a valid T.4 code or on the
  263.    first EOL after an invalid code.  The macro's parameter len will be the
  264.    run length, -1 on a normal EOL or -2 for the EOL following an error.  1D
  265.    coding only.
  266.  
  267.    As per T.4, run lengths >63 (make-up codes) should be added to the
  268.    subsequent (terminating) code.  The first run of a line is white and
  269.    colors alternate.
  270.  
  271.    Each node of the tree contains pointers to the next node for a '0' or a
  272.    '1' bit.  NULL pointers indicate terminal nodes in which case, the run
  273.    length (or -1 or -2) is given by the zlen or olen member and the search
  274.    continues with the node given by the znext or onext pointer.
  275.  
  276.    The decoding tree, stored in packed format (LSB to MSB plus guard bit),
  277.    is built by calling mktree() which returns a pointer to the initial
  278.    value of 't4p' to be used by the T4TST macro.
  279.  
  280. */
  281.  
  282. typedef struct dtree { 
  283.   struct dtree *zero, *one, *onext, *znext ; 
  284.   short int zlen, olen ;
  285. } dtree ;
  286.  
  287. #define T4TST(c,m) t4p = ( c & m ) ? \
  288. ( t4p->one  ? t4p->one  : ( T4CODE ( t4p->olen ), t4p->onext ) ) : \
  289. ( t4p->zero ? t4p->zero : ( T4CODE ( t4p->zlen ), t4p->znext ) ) ;
  290.  
  291. #define T4CTST(c) T4TST(c,0x80) ;  T4TST(c,0x40) ; \
  292.                   T4TST(c,0x20) ;  T4TST(c,0x10) ; \
  293.                   T4TST(c,0x08) ;  T4TST(c,0x04) ; \
  294.                   T4TST(c,0x02) ;  T4TST(c,0x01) ;
  295.  
  296. #define T4NODES 228
  297.  
  298. const short int pkdt4tree [] = {
  299.  
  300. 7,1,29,53,243,263,9,1,11,1,13,1,15,1,17,1,19,1,21,1,23,1,25,1,  
  301. 27,1,27,2,-2,31,49,43,33,75,35,37,4,10,121,39,41,173,4,63,4,0,  
  302. 79,45,95,47,93,4,1,71,51,167,4,2,55,61,57,59,4,3,67,69,4,4,63,65,  
  303. 4,5,83,4,6,4,7,2,128,4,8,4,9,87,73,109,4,11,89,77,99,4,12,117,  
  304. 103,81,107,4,13,85,2,64,4,14,4,15,4,16,4,17,119,91,203,4,18,4,19,127,  
  305. 97,131,4,20,129,137,101,143,4,21,123,105,145,4,22,4,23,147,111,155,  
  306. 113,115,4,24,149,151,4,25,153,4,26,4,27,163,4,28,165,209,125,  
  307. 4,29,4,30,4,31,4,32,4,33,4,34,133,135,4,35,4,36,4,37,4,38,139,141,  
  308. 4,39,4,40,4,41,4,42,4,43,4,44,4,45,4,46,4,47,4,48,4,49,4,50,4,51,4,52,  
  309. 4,53,4,54,157,2,192,159,161,4,55,4,56,4,57,4,58,4,59,4,60,4,61,4,62,  
  310. 175,169,181,171,197,2,256,2,320,2,384,2,1664,177,179,185,2,448,2,512,  
  311. 183,191,2,576,189,187,2,640,2,704,2,768,2,832,2,896,193,195,2,960,2,1024,  
  312. 2,1088,2,1152,199,201,2,1216,2,1280,2,1344,2,1408,205,207,2,1472,2,1536,  
  313. 2,1600,2,1728,235,211,213,217,215,223,2,1792,221,219,229,2,1856,2,1920,  
  314. 2,1984,2,2048,225,227,2,2112,2,2176,2,2240,2,2304,231,233,2,2368,2,2432,  
  315. 2,2496,2,2560,237,1,239,1,241,1,241,2,-1,245,261,247,265,249,267,  
  316. 273,251,271,253,255,2,12,281,257,303,259,307,2,0,2,1,2,4,2,3,2,2,  
  317. 2,6,2,5,269,2,7,2,9,2,8,2,10,2,11,291,275,277,279,2,13,283,287,2,14,  
  318. 2,15,299,313,285,383,2,16,289,309,2,17,357,423,293,295,321,297,317,  
  319. 2,18,363,327,301,331,2,19,305,341,2,20,339,2,21,349,333,311,347,2,22,  
  320. 315,351,2,23,361,379,319,389,2,24,323,371,325,367,2,25,397,395,329,  
  321. 2,26,2,27,2,28,2,29,335,337,2,30,2,31,2,32,2,33,2,34,2,35,343,345,  
  322. 2,36,2,37,2,38,2,39,2,40,2,41,2,42,2,43,353,355,2,44,2,45,2,46,2,47,  
  323. 359,393,2,48,2,49,2,50,2,51,365,377,2,52,403,399,369,401,2,53,  
  324. 373,4,64,375,409,2,54,407,405,2,55,381,387,2,56,415,385,391,2,57,2,58,  
  325. 417,2,59,2,60,419,2,61,4,256,2,62,2,63,4,128,4,192,421,4,320,  
  326. 4,384,4,448,4,512,4,576,4,640,4,704,4,768,4,832,4,896,4,960,411,413,  
  327. 4,1024,4,1088,4,1152,4,1216,4,1280,4,1344,4,1408,4,1472,4,1536,4,1600,  
  328. 4,1664,4,1728,449,425,427,431,429,437,4,1792,435,433,443,4,1856,4,1920,  
  329. 4,1984,4,2048,439,441,4,2112,4,2176,4,2240,4,2304,445,447,4,2368,4,2432,  
  330. 4,2496,4,2560,451,1,453,1,455,1,455,2,-1,
  331. -1 } ;
  332.  
  333.  
  334. /* Program options. Not changed except in main(). */
  335.  
  336. cap local = { DEFCAP } ;      /* -c  local capabilities */
  337. char *argv0 = "?" ;          /*     program name (argv[0]) */
  338. char *fnamepat= FNAMFT ;      /* -r  pattern for received file names */
  339. char **fnames = 0 ;          /* -t  files to send */
  340. char *getty = "" ;          /* -g  command for data calls */
  341. char *iopt[ MAXIOPT ] ;          /* -i  modem init commands */
  342. char *zopt[ MAXIOPT ] ;          /* -z  modem reset commands */
  343. char *lkfiles [ MAXLKFILE+1 ] ;      /* -x  lock files  */
  344. char localid  [ IDLEN + 1 ] ;      /* -l  local ID (telephone #) */
  345. char *verb = "ewin" ;          /* -v  verbosity level */
  346. int c1 = 0 ;              /* -o1 use class 1 protocol */
  347. int softadans = 0 ;          /* -oa use software adaptive answer */
  348. int igniniterr=0 ;          /* -oe ignore initialization errors */
  349. int niopt=0 ;              /*     number of init commands */
  350. int nzopt=0 ;              /*     number of reset commands */
  351. int cmdpause = T_CMD ;          /* -oz delay before each init command */
  352. int maxpgerr = 10 ;          /* -q  maximum errors per page */
  353. int nfiles=0 ;              /*     number of files to send */
  354. int share = 0 ;              /* -s  share fax device */
  355. int waitforcall = 0 ;          /* -w  wait for incoming call */
  356. u_char startchar = DC2 ;      /* -ox character to start reception */
  357.  
  358.  
  359.  
  360. /* Bit ordering: serial devices transmit LS bit first.  T.4/T.30 says MS
  361.    bit is sent first. `Normal' order therefore reverses bit order. */
  362.  
  363. u_char                           /* bit reversal lookup tables*/
  364.    reversebits [ 256 ] , normalbits [ 256 ] , 
  365.    *rxbitorder = normalbits , *txbitorder = normalbits ;
  366.  
  367. dtree *t4tree ;                /* T.4 decoding tree */
  368.  
  369. /* fax stream variables (private). */
  370.  
  371. u_char faxibuf [ RCVBUFSIZE ] ,        /* fax input stream. */
  372.   *faxip=faxibuf , *faxiq=faxibuf ;
  373.  
  374. u_char faxobuf [ SNDBUFSIZE ] ,        /* fax output stream. */
  375.   *faxop=faxobuf , *faxoq=faxobuf+SNDBUFSIZE ;
  376.  
  377. int faxdev=-1 ;                /* fax device file descriptor. */
  378.  
  379. /* session state variables. */
  380.  
  381. FILE *file=0 ;                /* current image file  */
  382. cap remote ;                            /* remote capabilities  */ 
  383. cap session ;                        /* session capabilities */
  384. char remoteid [ IDLEN + 1 ] ;        /* ID (tel no) of remote station */
  385. int crate = 19200 ;                /* CONNECT rate */
  386. int datamode=0 ;            /* true if answered in data mode */
  387. int decimate = 0 ;            /* drop 1/2 lines to get 98 lpi */
  388. int good=1 ;                /* page received OK */
  389. int hsc=-1 ;                /* hangup status code (Class 2) */
  390. int minlen = 0 ;            /* pad lines to this many bytes */
  391.  
  392.  
  393. /* Functions... */
  394.  
  395. /* Print time stamp. */
  396.  
  397. void tstamp( )
  398. {
  399.   static time_t last = 0 , now ;
  400.   char *fmt = 0, tbuf [ MAXTSTAMP ] ;
  401.  
  402.   now = time ( 0 ) ;
  403.  
  404.   if ( now - last >   0 ) fmt = " (%M:%S)" ;
  405.   if ( now - last > 600 ) fmt = " %c" ;
  406.  
  407.   if ( fmt ) {
  408.     strftime ( tbuf , MAXTSTAMP , fmt , localtime( &now ) ) ;
  409.     fputs ( tbuf , LOGF ) ;
  410.     last = now ; 
  411.   }
  412. }
  413.  
  414.  
  415. /* For systems without strerror(3) */
  416.  
  417. char *strerror( int i )       
  418. {
  419.   extern int sys_nerr;
  420.   extern char *sys_errlist[];
  421.   return ( i >= 0 && i < sys_nerr ) ? sys_errlist[i] : "Unknown Error" ;
  422. }
  423.  
  424.  
  425. /* Return string corresponding to character c. */
  426.  
  427. char *cname ( u_char c ) 
  428. {
  429. #define CNAMEFMT "<0x%02x>"
  430. #define CNAMELEN 6+1
  431.   static char *cname [ 256 ] = {        /* character names */
  432.   "<NUL>","<SOH>","<STX>","<ETX>", "<EOT>","<ENQ>","<ACK>","<BEL>",
  433.   "<BS>", "<HT>", "<LF>", "<VT>",  "<FF>", "<CR>", "<SO>", "<SI>", 
  434.   "<DLE>","<XON>","<DC2>","<XOFF>","<DC4>","<NAK>","<SYN>","<ETB>",
  435.   "<CAN>","<EM>", "<SUB>","<ESC>", "<FS>", "<GS>", "<RS>", "<US>" } ;
  436.   static char names[ (127-32)*2 + 129*(CNAMELEN) ], *p=names ;
  437.   static int i=0 ;
  438.     
  439.   if ( ! i ) 
  440.     for ( i=32 ; i<256 ; i++ ) {
  441.       cname [ i ] = p ;
  442.       sprintf ( p, i<127 ? "%c" : CNAMEFMT , i ) ;
  443.       p += strlen ( p ) + 1 ;
  444.     }
  445.  
  446.   return cname [ c ] ;
  447.  
  448. /* Return name of frame of type 'fr'. */
  449.  
  450. const char *frname ( int fr )
  451. {
  452. static struct framenamestruct {  int code ;  const char *name ; } 
  453. framenames [] = {
  454.  {DIS,"DIS"},{CSI,"CSI"},{NSF,"NSF"},{CFR,"CFR"},{FTT,"FTT"},{MCF,"MCF"},
  455.  {RTN,"RTN"},{RTP,"RTP"},{PIN,"PIN"},{PIP,"PIP"},{DCS,"DCS"},{TSI,"TSI"},
  456.  {NSS,"NSS"},{CRP,"CRP"},{DCN,"DCN"},{EOM,"EOM"},{MPS,"MPS"},{EOP,"EOP"},
  457.  {PRI_EOM,"PRI-EOM"},{PRI_MPS,"PRI-MPS"},{PRI_EOP,"PRI-EOP"},
  458.  {DTC,"DTC"},{CIG,"CIG"},{NSC,"NSC"}, {0,0} }, *p ;
  459.  
  460.   for ( p=framenames ; p->code && p->code != fr ; p++ ) ;
  461.   return p->code ? p->name : "UNKNOWN" ;
  462. }
  463.  
  464.  
  465. /* Print a message with a variable number of printf()-type arguments if the
  466.    first character appears in the verb[ose] string.  Other leading
  467.    characters and digits do additional actions: + allows the message to be
  468.    continued on the same line, '-' buffers the message instead of printing
  469.    it, E, and W expand into strings, S prints the error message for the
  470.    most recent system error, 0-4 set the return value, a space is skipped
  471.    and ends prefix.  Returns 0 if no prefix digit. */
  472.  
  473. int msg ( const char *fmt, ... ) 
  474.   int err=0, dolf=1, flush=1 ;
  475.   char *ps="", *pe="", *pw="" ;
  476.   const char *p ;
  477.   static int atcol1=1 ;
  478.   va_list ap ;
  479.   va_start ( ap, fmt ) ;
  480.  
  481.   for ( p=fmt ; *p ; p++ ) {
  482.     switch ( *p ) {
  483.     case ' ': p++ ; goto print ;
  484.     case 'A': break ;                   /* program args */
  485.     case 'C': break ;                   /* commands/responses */
  486.     case 'M': break ;                   /* modem dialogue */
  487.     case 'N': break ;                   /* negotiation */
  488.     case 'E': pw = "Error: " ; break ;
  489.     case 'H': break ;                   /* HDLC frame data */
  490.     case 'I': break ;                   /* information */
  491.     case '+': dolf = 0 ; break ;
  492.     case '-': flush = 0 ; break ;
  493.     case 'R': break ;                   /* reception errors */
  494.     case 'S': ps = strerror ( errno ) ; break ;
  495.     case 'W': pw = "Warning: " ; break ;
  496.     case '0': case '1': case '2': case '3': case '4': case '5': 
  497.       err = *p - '0' ; break ;
  498.     default: goto print ;
  499.     }
  500.   }
  501.  
  502.   print:  
  503.   if ( strchr ( verb , tolower ( *fmt ) ) ) {
  504.     if ( atcol1 ) fprintf ( LOGF , "%s: %s%s" , argv0 , pe , pw ) ;
  505.     vfprintf( LOGF, p , ap ) ;
  506.     fputs ( ps , LOGF ) ;
  507.     if ( ( atcol1 = dolf ) ) {
  508.       tstamp ( ) ; 
  509.       fputs ( "\n" , LOGF ) ;
  510.     }
  511.     if ( flush ) fflush ( LOGF ) ;
  512.   }
  513.  
  514.   va_end ( ap ) ;
  515.   return err ;
  516. }
  517.  
  518.  
  519. /* Unpack the decoding tree. If the LS bit is 1, the entry is a
  520.    pointer to the next node in a code word, else it is a terminal
  521.    node and the value is a pointer to where to continue scanning
  522.    for the next code word and the following value is the run
  523.    length (or -1 or -2). */
  524.  
  525. dtree *unpktree ( )
  526. {
  527.   static dtree nodes [ T4NODES ], *p ;
  528.   const short int *l ;
  529.   for ( p=nodes, l=pkdt4tree ; *l > 0 ; p++ ) {
  530.     if ( p - nodes >= T4NODES ) {
  531.       fprintf ( stderr, "error in T.4 decoding tree\n" ) ; break ;
  532.     }
  533.     if ( *l & 1 ) { p->zero = nodes + *l++/2 ; }
  534.     else { p->znext = nodes + *l++/2 ; p->zlen = *l++ ; } ;
  535.     if ( *l & 1 ) { p->one  = nodes + *l++/2 ; } 
  536.     else { p->onext = nodes + *l++/2 ; p->olen = *l++ ; } ;
  537.   }
  538.   return nodes + 1 ;        /* search starts at node 1 (white runs) */
  539. }
  540.  
  541.  
  542. /* millisecond delays (for systems without usleep). */
  543.  
  544. void msleep ( int t )
  545. {
  546.   struct timeval timeout ;
  547.   timeout.tv_sec  = t / 1000 ; 
  548.   timeout.tv_usec = ( t % 1000 ) * 1000 ;
  549.   if ( select ( 1 , 0 , 0 , 0 , &timeout ) < 0 ) 
  550.     msg ("ES2select failed in msleep:") ;
  551. }
  552.  
  553. /* Return number of characters ready to read or < 0 on error.  t
  554.    is tenths of a second of idle time before timing out.  If t is
  555.    negative, waits forever. */
  556.  
  557. int faxdata ( int t )
  558. {
  559.   int n ;
  560.   fd_set fds ;
  561.  
  562.   struct timeval timeout ;
  563.  
  564.   if ( faxdev < 0 ) msg ("Ecan't happen (faxdata)") ;
  565.  
  566.   timeout.tv_sec  = t / 10 ; 
  567.   timeout.tv_usec = ( t % 10 ) * 100000 ;
  568.  
  569.   FD_ZERO ( &fds ) ;
  570.   FD_SET ( faxdev , &fds ) ;
  571.  
  572.   n = select ( faxdev+1 , &fds , 0 , 0 , t<0 ? 0 : &timeout ) ;
  573.   if ( n < 0 ) msg("ES2select failed in faxdata:") ;
  574.  
  575.   return n ;
  576. }
  577.  
  578. /* faxundrflw is called only by the faxgetc() macro when the buffer is
  579.    empty.  t is maximum idle time before giving up. Returns number of
  580.    characters read or EOF on timeout or errors.  */
  581.  
  582. int faxundrflw ( int t )
  583.   int n = faxdata ( t ) ;
  584.  
  585.   if ( n > 0 )
  586.     if ( ( n = read( faxdev , faxibuf , RCVBUFSIZE ) ) < 0 ) 
  587.       msg ("ES2fax device read:") ;
  588.  
  589.   faxiq = ( faxip = faxibuf ) + ( n > 0 ? n : 0 ) ;
  590.  
  591.   return n > 0 ? n : EOF ;
  592.  
  593. /* faxgetc is a macro like getc().  It returns the next character
  594.    from the fax device or EOF after idle time t. */
  595.  
  596. #define faxgetc(t) ( faxip >= faxiq && faxundrflw(t) == EOF ? EOF : \
  597.             *(u_char*)faxip++ )
  598.  
  599. /* A function like faxgetc that also removes DLE escapes, detects DLE-ETX
  600.    terminators and fixes bit order. Does not ignore invalid escape
  601.    sequences. Returns the character read, EOF on error/timeout, or -2 on
  602.    DLE-ETX.  */
  603.  
  604. int faxgetdatac ( int t )
  605. {
  606.   int c ;
  607.   return ( c = faxgetc(t) ) == DLE && ( c = faxgetc(t) ) == ETX ? -2 : 
  608.     normalbits [ c & 0xff ] ;
  609. }
  610.  
  611.  
  612. /* Get a modem response into buffer s, storing up to n bytes.  The response
  613.    begins with most recent non-control character and ends with CR/LF.
  614.    Returns s or null if times-out in t deciseconds or on i/o error. Trace
  615.    messages are buffered to reduce possible timing problems. */
  616.  
  617. char *faxgets( char *s , int n , int t )
  618. {
  619.   int c=0, sta=0 ;
  620.   char *p = s ;
  621.  
  622.   while ( sta < 4 ) {
  623.     if ( ( c = faxgetc( t ) ) == EOF ) break ;
  624.     c &= 0x7f ;
  625.     if ( ! sta ) msg ( "M-+ [" ) ; 
  626.     msg ( "M-+ %s" , cname ( c ) ) ;
  627.     switch ( sta ) {
  628.     case 0 :
  629.     case 1 : sta =               ( iscntrl ( c ) ? 1 : (p=s, 2) ) ; break ;
  630.     case 2 : sta = c == CR ? 3 : ( iscntrl ( c ) ? 1 :       2  ) ; break ;
  631.     case 3 : sta = c == LF ? 4 : ( iscntrl ( c ) ? 1 : (p=s, 2) ) ; break ;
  632.     default: msg ( "Ecan't happen (faxgets)" ) ;
  633.     }
  634.     if ( sta == 2 && p < s+n-1 ) *p++ = c ;
  635.   }
  636.  
  637.   *p = 0 ;
  638.   if ( p >= s+n-1 ) msg ( "W- modem response overflow" ) ;
  639.   if ( sta ) msg ( "M- %s]" , c == EOF ? "<timeout>" : "" ) ;
  640.  
  641.   return c == EOF ? 0 : s ;
  642. }
  643.  
  644.  
  645. /* Write the fax output buffer to fax output device. To allow zero-fill
  646.    underflow padding, should be called after writing the EOL zero
  647.    byte. Warns if called with full buffer (presumably called from
  648.    faxputc()). Returns 0 or EOF on error. */
  649.  
  650. int faxflush ( )
  651.   int n=0 ;
  652.   u_char *p = faxobuf ;
  653.  
  654.   if ( faxdev < 0 ) msg ("Ecan't happen (faxflush)") ;
  655.  
  656.   if ( faxop >= faxoq ) msg ("Wfax output buffer overflow") ;
  657.  
  658.   while ( p < faxop && ( n = write( faxdev , p , faxop - p ) ) >= 0 )
  659.     p += n ? n : msg ( "W0wrote %d of %d bytes" , n , faxop - p ) ;
  660.  
  661.   return n >= 0 ? (faxop = faxobuf , 0) : (msg ("ESfax device write:") , EOF) ;
  662.  
  663. /* faxputc() is a macro like putc().  It returns the character written or
  664.    EOF on error. */
  665.  
  666. #define faxputc(c) ( faxop >= faxoq && faxflush() == EOF ? EOF : \
  667.             (u_char) ( *faxop++ = (c) ) )
  668.  
  669. /* faxobytes() returns number of bytes in fax output buffer */
  670.  
  671. #define faxobytes() ( faxop - faxobuf ) 
  672.  
  673.  
  674. /* A function like faxputc but also escapes DLEs and sets proper bit
  675.    order. */
  676.  
  677. int faxputdatac ( u_char c )
  678. {
  679.   int x ;
  680.   x  = normalbits [ c ] ;
  681.   if ( x == DLE ) x = faxputc ( x ) ;
  682.   return x < 0 ? x : faxputc ( x ) ;
  683. }
  684.  
  685.  
  686. /* Send character or string to modem immediately (for commands).  Returns
  687.    like putc() and puts(). */
  688.  
  689. int faxputcnow ( char c ) 
  690.   return faxputc ( c ) < 0 ? EOF : ( faxflush() ? EOF : c ) ; 
  691. }
  692.  
  693. int faxputs ( const char *s )
  694. {
  695.   int n=0 ;
  696.   while ( s && *s && ( n = faxputcnow ( *s++ ) ) != EOF ) ;
  697.   return n ;
  698. }
  699.  
  700.  
  701. /* Compare current termios state with termios struct t. Returns 0 if equal,
  702.    1 otherwise. */
  703.  
  704. int checktermio ( struct termios *t )
  705. {
  706.   struct termios s ;
  707.   return tcgetattr ( faxdev , &s ) != 0 ||
  708.     t->c_iflag != s.c_iflag || t->c_oflag != s.c_oflag
  709.       || t->c_lflag != s.c_lflag || t->c_cflag != s.c_cflag
  710.     || t->c_cc[VMIN] != s.c_cc[VMIN] || t->c_cc[VTIME]!= s.c_cc[VTIME] ;
  711. }
  712.  
  713.  
  714. /* Set serial port mode. First time through saves initial settings. Sets
  715.    raw, 8-bit, 19.2 kbps mode with no flow control or as required. Returns
  716.    0 or 2 on error. */
  717.  
  718. int ttymode ( enum ttymodes mode )
  719. {
  720.   int err=0 ;         
  721.   static int saved=0 ;
  722.   static struct termios old, t ;
  723.  
  724.   if ( faxdev < 0 ) msg ("Ecan't happen (ttymode/faxdev)") ;
  725.  
  726.   tcdrain ( faxdev ) ;
  727.   tcflush ( faxdev , TCIOFLUSH ) ; /* make sure */
  728.  
  729.   if ( ! saved ) { 
  730.     if ( tcgetattr ( faxdev , &t ) ) {
  731.       err = msg ("ES2tcgetattr failed:") ;
  732.     } else {
  733.       old = t ; 
  734.       saved = 1 ;
  735.     } 
  736.   } else {
  737.     if ( checktermio ( &t ) ) msg ( "Wterminal mode corrupted" ) ;
  738.   }
  739.  
  740.   t.c_iflag = IGNBRK | IGNPAR | IXANY ;
  741.   t.c_oflag = 0 ;
  742.   t.c_cflag = CS8 | CREAD | CLOCAL | HUPCL ;
  743.   t.c_lflag = 0 ;
  744.   
  745.   t.c_cc[VMIN]  = 1 ; 
  746.   t.c_cc[VTIME] = 0 ; 
  747.  
  748.   cfsetospeed ( &t , B19200 ) ; 
  749.   cfsetispeed ( &t , B19200 ) ; 
  750.  
  751.   if ( ! err ) 
  752.     switch ( mode ) {
  753.     case  COMMAND :                                         break ;
  754.     case  DROPDTR : cfsetospeed ( &t , B0 ) ;               break ;
  755.     case     SEND : t.c_iflag |= IXON ;                     break ;
  756.     case ORIGINAL : if ( saved ) t = old ;                  break ;
  757.           default : err = msg ("E2can't happen(ttymode)") ; break ;
  758.     }
  759.   
  760.   tcdrain ( faxdev ) ;        /* make *sure* output done B4 turn off f/c */
  761.   tcflow ( faxdev , TCOON ) ;    /* in case XON got lost */
  762.  
  763.   if ( ! err && tcsetattr ( faxdev , TCSANOW , &t ) )
  764.     err = msg ( "ES2tcsetattr failed:" ) ;
  765.  
  766.   if ( !err && checktermio ( &t ) ) 
  767.     err = msg ( mode == ORIGINAL ? 
  768.            "W0terminal mode not restored properly" : 
  769.            "E2terminal mode not set properly" ) ;
  770.   
  771.   return err ;
  772. }
  773.  
  774.  
  775. /* Convert capability string to cap struct. Returns 0 or 2 on errors. */
  776.  
  777. int str2cap ( char *s, cap c )
  778. {
  779.   int err=0, i=0, n ;
  780.   char *p ;
  781.  
  782.   for ( n=0, p=s ; ! err && *p && i<NCAP ; p++ )
  783.     if ( isdigit ( *p ) ) c [ n++ ] = *p - '0' ;
  784.     else if ( isspace ( *p ) || *p == ',' ) ;
  785.     else err = msg ("E2invalid character (%c) in (%s)", *p , s ) ;
  786.  
  787.   if ( n < NCAP ) msg ( "W0missing value(s) in capability \"%s\"", s ) ;
  788.  
  789.   for ( i=0 ; i<n ; i++ ) 
  790.     if ( c [ i ] > capmax [ i ] || c [ i ] < 0 ) 
  791.       err = msg ( "E2%s = %d is %s", s , t30tab[i].name , c [ i ], 
  792.         c[i]<0 ? "negative" : "too big" ) ;
  793.   
  794.   return err ;
  795. }
  796.  
  797. /* Print cap[ability] 'c' using text values and prefix 's'. */
  798.  
  799. void printcap ( char *s , cap c )
  800. {
  801.   int i ;
  802.   msg ( "N-+ %s" , s ) ;
  803.   for ( i=0 ; i<NCAP ; i++ ) 
  804.     msg ( "N-+  %s" , c[i] > capmax [ i ] || c[i] < 0 ?  "ERROR" :
  805.      capvaluestr [ i ] [ c[i] ] ) ;
  806.   msg ( "N-" , s ) ;
  807. }
  808.  
  809.  
  810. /* Convert a cap[ability] 'c' to a DIS/DCS/DTC FIF 'fif' of 'len' bytes.
  811.    Converts into DIS format if 'isdis' is true, else into DCS/DTC
  812.    format. Returns 0 or 3 on internal error (bad conversion tables). */
  813.  
  814. int mkdis ( cap c , u_char *fif , int len , int isdis ) 
  815. {
  816.   int err=0, i, j, k ;
  817.   t30tabst *p ;
  818.  
  819.   if ( len < 3 || len > 5 ) 
  820.     len = msg ( "W3bad DCS/DIS length (%d) set to 3" , len ) ;
  821.  
  822.   fif[0] = 0 ;
  823.   fif[1] = isdis ? 0xc0 : 0x40 ;
  824.   for ( i=2 ; i<len-1 ; i++ ) fif[i] = 0x01 ;       /* add extension bits */
  825.   fif[i] = 0 ;
  826.  
  827.   for ( i=0 ; p=t30tab+i, i<NCAP ; i++ ) {
  828.  
  829.     j = c [ i ] ;
  830.     if ( j > capmax [ i ] || j < 0 ) {
  831.       j = 0 ;
  832.       err = msg ( "E3mkdis: bad %s = %d set to 0", p->name, j ) ;
  833.     }
  834.     k = ( isdis ? p->captodis : p->captodcs ) [ j ] ;
  835.     if ( k == X ) {
  836.       k = 0 ;
  837.       err = msg ( "E3mkdis: can't happen (invalid %s)", p->name ) ;
  838.     }
  839.     if ( p->byte < len ) fif [ p->byte ] |=  k << p->shift ;
  840.   }
  841.   return err ;
  842. }
  843.  
  844. /* Return length of DIS/DTC FIF (counts extension bits). */
  845.  
  846. int dislen ( u_char *fif )
  847. {
  848.   int n ;
  849.   for ( n=3 ; fif [ n-1 ] & 0x01 ; n++ ) ;
  850.   return n ;
  851. }
  852.  
  853. /* Convert received DIS/DCS/DTC FIF to cap. Returns 0 or 3 on error (bad
  854.    DIS/DCS field). */
  855.  
  856. int mkcap ( u_char *fif, cap c , int dis ) 
  857. {
  858.   int err=0, i, j, k, len ;
  859.   t30tabst *p ;
  860.  
  861.   len = dislen ( fif ) ;
  862.  
  863.   for ( i=0 ; i<NCAP ; i++ ) {
  864.     p=t30tab+i ;
  865.     if ( p->byte >= len ) {
  866.       c [ i ] = 0 ;
  867.     } else {
  868.       j = fif [ p->byte ] >> p->shift & p->mask ;
  869.       k = ( dis ? p->distocap : p->dcstocap ) [ j ] ;
  870.       if ( k == X ) {
  871.     c [ i ] = 0 ;
  872.     err = msg("E3mkcap: bad %s field (%d) set to 0", p->name, j) ;
  873.       } else { 
  874.     c [ i ] = k ;
  875.       }
  876.     }
  877.   }
  878.   return err ;
  879. }
  880.  
  881.  
  882. /* Compute compatible local/remote capabilities. As side effect, sets
  883.    minimum line length and decimation. This routine is used by the sending
  884.    station only (or both in Class 2). Returns 0 if OK or 3 if no compatible
  885.    settings possible. */
  886.  
  887. int mincap ( cap local, cap remote, cap session )
  888. {
  889.   int err=0, i ;
  890.   int msttab[2][8] = { { 0,1,3,3,5,5,7,7 } , { 0,1,1,3,3,5,5,7 } } ;
  891.  
  892.   for ( i=0 ; i<NCAP && i!=ST ; i++ )
  893.     session[i] = remote[i] < local[i] ? remote[i] : local[i] ;
  894.  
  895.   session[ST] = msttab [ session[VR] ] [ remote[ST] ] ;
  896.  
  897.   minlen = (cps[session[BR]] * delay[session[ST]] + 500) / 1000 ;
  898.  
  899.   decimate = local[VR] == 1 && session[VR] == 0 ;
  900.  
  901.   printcap ( "local  ", local ) ;
  902.   printcap ( "remote ", remote ) ;
  903.   printcap ( "session", session ) ;
  904.   msg ( "N- padding to %d bytes/line.%s", minlen, 
  905.        decimate ? " reducing 198->96 lpi." : "" ) ;
  906.  
  907.   if ( local[WD] != session[WD] || local[LN] != session[LN] || 
  908.       local[DF] != session[DF] ) 
  909.     err = msg ("E3can't convert image to remote capabilities" ) ;
  910.  
  911.   return err ;
  912. }
  913.  
  914.  
  915. /* Search for a match to the string s in a null-terminated array of
  916.    possible prefix strings pointed to by p.  The first character of each
  917.    prefix string is skipped.  Returns pointer to the table entry or NULL if
  918.    not found.  */
  919.  
  920. char *strtabmatch ( char **p, char *s )
  921. {
  922.   while ( *p && strncmp ( *p+1 , s , strlen ( *p+1 ) ) ) p++ ;
  923.   return ( ! *p || **p == '-' ) ? NULL : *p ;
  924. }
  925.  
  926.  
  927. /* Send command to modem and check responses.  Collects pending
  928.    (unexpected) responses and then pauses for inter-command delay
  929.    (cmdpause) if t is negative.  Writes command s to modem if s is not
  930.    null.  Reads responses and terminates when a response is one of the
  931.    prompts in responses[] or if times out in t deciseconds.  Notes and
  932.    processes important class 2 responses (FPTS: Page Transfer Status, FHNG:
  933.    HaNGup status, and FDCS: Current Session capabilities).  Repeats command
  934.    if detects a RING response (probable collision). Returns the first
  935.    character of the matching prefix string (e.g. 'O' for OK, 'C' for
  936.    CONNECT, etc.)  or EOF if no such response was received within timeout
  937.    t. */
  938.  
  939. int cmd ( const char *s , int t )
  940. {
  941.   char buf [ CMDBUFSIZE ] , *p = "" ;
  942.   int ppr ;
  943.  
  944.  retry:
  945.  
  946.   while ( s && faxgets ( buf , CMDBUFSIZE , t<0 ? cmdpause : 0 ) )
  947.     msg ( "W- unexpected response \"%s\"", buf ) ;
  948.  
  949.   msg ( s ? "C- command  \"%s\"" : "C- waiting" , s ) ;
  950.  
  951.   if ( s ) { faxputs ( "AT" ) ; faxputs ( s ) ; faxputcnow ( CR ) ; }
  952.  
  953.   while ( t && ( p = faxgets( buf , CMDBUFSIZE , t<0 ? -t : t ) ) ) {
  954.  
  955.     msg ( "C- response \"%s\"" , p ) ;
  956.  
  957.     if ( ! strncmp ( buf, "DATA" , 4 ) ||
  958.     ! strncmp ( buf, "CONNECT DATA" , 12 ) )
  959.       datamode = 1 ;
  960.     if ( ! strncmp ( buf, "+FDCS:", 6 ) && ! str2cap ( buf+6 , session ) ) 
  961.       mincap ( local, session, session ) ; /* set decimation & minlen */
  962.     if ( sscanf ( buf , "+FPTS: %d", &ppr ) > 0 ) good = ppr & 1 ;
  963.     sscanf ( buf, "+FHNG: %d", &hsc ) ;
  964.     sscanf ( buf, "CONNECT %d", &crate ) ;
  965.  
  966.     if ( ( p = strtabmatch ( (char**) prompts , buf ) ) ) break ;
  967.  
  968.     if ( ! strncmp ( buf, "RING", 4 ) ) { msleep(100) ; goto retry ; }
  969.   }
  970.  
  971.   return p ? *p : EOF ;
  972. }
  973.  
  974. /* Send command to modem and wait for either of two possible replies after
  975.    testing (and possibly setting) current error status via err pointer. */
  976.  
  977. void ckcmd ( int *err, const char *s, int t, int r1, int r2 )
  978. {
  979.   int c ;
  980.   if ( ! *err )
  981.     if ( ( c = cmd ( s, t ) ) != r1 && c != r2 ) 
  982.       if ( c == EOF ) 
  983.     *err = msg ("E3modem command (%s) timed out", s ? s : "none" ) ;
  984.       else
  985.     *err = msg ("E3wrong response to command (%s)", s ? s : "none" ) ;
  986. }
  987.  
  988.  
  989. /* Test for UUCP lock file & remove stale locks. Returns 0 on null file
  990.    name or if no longer locked, 1 if locked by another pid, 2 on error, 3
  991.    if locked by us. */
  992.  
  993. int ttlocked ( char *fname )
  994. {
  995.   int err=0 ;
  996.   FILE *f ;
  997.   pid_t pid = 0 ;
  998.   char buf [ FILENAME_MAX ] = "" ;
  999.  
  1000.   if ( fname && *fname == HDBLKFLAG ) fname++ ;
  1001.  
  1002.   if ( fname && ( f = fopen ( fname , "r" ) ) ) {
  1003.     if ( fread ( buf, sizeof(char), FILENAME_MAX-1, f )  == sizeof(pid_t) || 
  1004.     sscanf ( buf , "%d" , &pid ) != 1 ) pid = * (pid_t *) buf ;
  1005.     if ( kill ( pid , 0 ) && errno == ESRCH )
  1006.       if ( unlink ( fname ) ) err = 
  1007.     msg ( "ES2can't remove stale lock %s from pid %d:" , fname , pid ) ;
  1008.       else err = 
  1009.     msg ( "I0removed stale lock %s from pid %d" , fname , pid ) ;
  1010.     else 
  1011.       if ( pid != getpid() ) err = 1 ;
  1012.       else err = 3 ; 
  1013.     fclose ( f ) ;
  1014.   }
  1015.   return err ;
  1016. }
  1017.  
  1018. /* Create UUCP (text or binary) lock file.  Returns 0 on null
  1019.    file name or if created, 1 if locked by another pid, 2 on
  1020.    error, 3 if locked by us. */
  1021.  
  1022. int ttlock ( char *fname )
  1023. {
  1024.   int err=0, dirlen, hdb=0 ;    
  1025.   FILE *f=0 ;    
  1026.   pid_t pid = getpid ( ) ;
  1027.   char *p , buf [ FILENAME_MAX ] = "" ;
  1028.  
  1029.   if ( fname && *fname == HDBLKFLAG ) { fname++ ; hdb=1 ; }
  1030.  
  1031.   if ( fname && ! ( err = ttlocked ( fname ) ) ) {
  1032.     dirlen = ( p = strrchr( fname , '/' ) ) ? p-fname+1 : strlen ( fname ) ;
  1033.     sprintf ( buf , "%.*sTMP..%05d" , dirlen , fname , pid ) ;
  1034.     if (  ( f = fopen( buf, "w" ) )  && 
  1035.     ( hdb ? 
  1036.      (fprintf(f, "%10d\n", pid)>0) : fwrite(&pid, sizeof(pid_t), 1, f) )
  1037.     ) {
  1038.       if ( rename ( buf , fname ) == 0 ) chmod ( fname , 0444 ) ;
  1039.       else if ( ! ( err = ttlocked ( fname ) ) )
  1040.     err = msg ( "ES2can't rename lock file %s to %s:\n", buf, fname ) ;
  1041.     } else {
  1042.       err = msg ( "ES2can't open/write pre-lock file %s:\n", buf ) ;
  1043.     }
  1044.   }
  1045.   if ( f ) { fclose ( f ) ; if ( err ) unlink ( buf ) ; }
  1046.   return err ;
  1047. }
  1048.  
  1049.  
  1050. /* Remove lock file.  Returns 0 on null file name, doesn't exist, or was
  1051.    removed, 1 if the lock is to another pid, 2 on errors. */
  1052.  
  1053. int ttunlock ( char *fname )
  1054. {
  1055.   int err = 0 ;
  1056.  
  1057.   if ( fname && *fname == HDBLKFLAG ) { fname++ ; }
  1058.  
  1059.   if ( fname && ( err = ttlocked ( fname ) ) ) {
  1060.     if ( err == 1 ) msg ( "Ewon't remove lock %s (not ours)" , fname ) ;
  1061.     if ( err == 3 )
  1062.       if ( unlink ( fname ) ) err = msg ( "ES2can't remove lock %s:", fname ) ;
  1063.       else err = 0 ;
  1064.   }
  1065.   return err ;
  1066. }
  1067.  
  1068.  
  1069. /* Lock all lock files.  Returns 0 if all locks [already] applied, 1 if any
  1070.    are locked to other pids, 2 on any errors. */
  1071.  
  1072. int lockall ( )
  1073.   int err = 0 ;
  1074.   char **p = lkfiles ;
  1075.   while ( *p && ! err ) 
  1076.     if ( ( err = ttlock ( *p++ ) ) == 3 ) err = 0 ; 
  1077.   return err ; 
  1078. }
  1079.  
  1080. /* Remove all lock files.  Returns 0 if all locks removed, 2 on errors. */
  1081.  
  1082. int unlockall ( )
  1083.   int err = 0 ;
  1084.   char **p = lkfiles ;
  1085.   while ( *p ) if ( ttunlock ( *p++ ) ) err = 2 ; 
  1086.   return err ; 
  1087. }
  1088.  
  1089. /* Resynchronize modem from an unknown state.  If no immediate response,
  1090.    try pulsing DTR low (needs &D{2,3,4}), and cancelling data or fax data
  1091.    modes.  In each case, discard any responses for about 2 seconds and then
  1092.    try command s.  Returns 0 if OK or 4 if no response.  */
  1093.  
  1094. int faxsync( char *s )
  1095. {
  1096.   int err=0, method=0 ;
  1097.  
  1098.   while ( ! err ) {
  1099.     switch ( method++ ) {
  1100.     case 0 : 
  1101.       break ;
  1102.     case 1 : 
  1103.       msg ("Isync: dropping DTR") ;
  1104.       ttymode ( COMMAND ) ; msleep ( 200 ) ;
  1105.       ttymode ( DROPDTR ) ; msleep ( 200 ) ;
  1106.       ttymode ( COMMAND ) ; 
  1107.       break ;
  1108.     case 2 : 
  1109.       msg ("Isync: sending escape") ;
  1110.       faxputs ( DLE_ETX ) ; 
  1111.       msleep ( 1500 ) ;
  1112.       faxputs ( "+++" ) ; 
  1113.       break ;
  1114.     case 3 :
  1115.       err = msg ("E4sync: modem not responding") ;
  1116.       continue ;
  1117.     }
  1118.     while ( cmd ( 0 , method ? TO_RESET : 1 ) != EOF ) ;
  1119.     if ( cmd ( s , -TO_RESET ) == OK ) break ;
  1120.   }
  1121.   return err ;
  1122.  
  1123.  
  1124. /* Terminate session.  Makes sure modem is responding, sends modem reset
  1125.    commands, resets fax device to original state, removes lock files. */
  1126.  
  1127. int end_session ( )
  1128. {
  1129.   int i, err ;
  1130.   err = faxsync ( "Q0V1" ) ;
  1131.  
  1132.   for ( i=0 ; ! err && i<nzopt ; i++ )
  1133.     if ( cmd( zopt[i] , -TO_RESET ) != OK  && ! igniniterr )
  1134.       err = msg ("E3modem reset command (%s) failed", zopt[i]) ;
  1135.  
  1136.   if ( ! err ) err = ttymode ( ORIGINAL ) ;
  1137.   unlockall ( ) ;
  1138.   return err ;
  1139.     
  1140.  
  1141. /* signal handler: hang up and exit */
  1142.  
  1143. void onsig ( int sig ) 
  1144.   msg ( "Eterminating on signal %d", sig ) ; 
  1145.   end_session ( ) ;
  1146.   msg ("Idone, returning 5") ;
  1147.   exit(5) ; 
  1148.  
  1149.  
  1150. /* Initialize session.  Try locking and opening fax device until opened or
  1151.    get error. Then set tty modes, register signal handler, setup
  1152.    modem. Returns 0 if OK, 2 on errors, 3 if initialization failed, 4 if no
  1153.    modem response. */
  1154.  
  1155. int begin_session ( char *faxfile )
  1156. {
  1157.   int i , err=0 , busy=0 , flags;
  1158.  
  1159.   do {
  1160.     err = lockall ( ) ;
  1161.     
  1162.     if ( ! err ) {
  1163.       faxdev = open ( faxfile , O_RDWR | O_NDELAY ) ;
  1164.       if ( faxdev < 0 )
  1165.     if ( errno == EBUSY ) err = 1 ; 
  1166.     else err = msg ( "ES2fax device open\n%s:", faxfile ) ;
  1167.       if ( ! err )
  1168.     if ( ( flags = fcntl( faxdev, F_GETFL, 0 ) ) < 0 ||
  1169.         fcntl( faxdev, F_SETFL, ( flags & ~O_NDELAY ) ) < 0 )
  1170.       err = msg ( "ES2fax device fcntl\n%s:", faxfile ) ;
  1171.     }
  1172.     
  1173.     if ( err == 1 ) { 
  1174.       if ( busy++ < 1 ) 
  1175.     msg ( "Wfax device %s locked or busy. waiting...", faxfile ) ;
  1176.       sleep ( LOCKPOLLDELAY ) ;
  1177.     }
  1178.  
  1179.   } while ( err == 1 ) ;
  1180.   
  1181.   if ( ! err ) msg ( "Iopened %s on fd %d", faxfile, faxdev ) ;
  1182.  
  1183.   if ( ! err ) err = ttymode ( COMMAND ) ;
  1184.   
  1185.   for ( i=0 ; ! err && catch [ i ] ; i++ ) 
  1186.     if ( signal ( catch [ i ] , onsig ) == SIG_ERR ) 
  1187.       err = msg ( "ES2can't set signal %d handler:", catch [ i ] ) ;
  1188.   
  1189.   if ( !err ) err = faxsync("Q0V1") ;
  1190.  
  1191.   for ( i=0 ; ! err && i<niopt ; i++ )
  1192.     if ( cmd( iopt[i] , -TO_RESET ) != OK && ! igniniterr )
  1193.       err = msg ("E3modem initialization command (%s) failed", iopt[i]) ;
  1194.  
  1195.   return err ;
  1196. }
  1197.  
  1198.  
  1199. /* Position `file' to start of page p (1...nfiles).  Assumes global
  1200.    variables 'fnames' and 'nfiles,' have been initialized.  This function
  1201.    looks ahead to see if there are more pages and if they are of a
  1202.    different format.  Eventually will handle multi-page files with embedded
  1203.    format information (e.g. TIFF-F).  Sets ppm to MPS if more pages to be
  1204.    sent with same format, EOM if more pages with different format, EOP if
  1205.    no more pages. Returns 0 if OK, 2 on errors.  Currently sets ppm to MPS
  1206.    or EOP only.  */
  1207.  
  1208. int rdpage ( int p , int *ppm )
  1209. {
  1210.   int err=0 ;
  1211.  
  1212.   if ( file && fclose ( file ) ) msg ("ES2file close:") ; 
  1213.  
  1214.   if ( p <= nfiles && p > 0 ) {
  1215.     if ( ( file = fopen ( fnames[p-1] , "rb" ) ) ) {
  1216.       msg ( "Iopened \"%s\" (p %d/%d)", fnames[p-1] , p, nfiles ) ;
  1217.       *ppm = p >= nfiles ? EOP : MPS ;
  1218.     } else {
  1219.       err = msg ("ES2 file open\n%s:", fnames[p-1]) ;
  1220.     }
  1221.   } else {
  1222.     err = msg ("E2 bad page number (%d)", p ) ;
  1223.   }
  1224.  
  1225.   return err ;
  1226. }
  1227.  
  1228. /* Same as rdpage() but creates new file name and opens `file' for
  1229.    writing. If page is -1 removes the most recently opened file. Assumes
  1230.    'fnampat' contains the strftime(3) pattern to be used for generating
  1231.    file names. Returns 0 if OK, 2 on errors. */
  1232.  
  1233. int wrpage ( int p )
  1234. {
  1235.   int err=0 ;
  1236.   static char fname [ FILENAME_MAX + 1 ] , base [ FILENAME_MAX + 1 ] ;
  1237.   time_t t ;
  1238.  
  1239.   t = time(0)  ;
  1240.   if ( ! *base ) strftime( base, FILENAME_MAX, fnamepat, localtime ( &t ) ) ;
  1241.  
  1242.   if ( file && fclose ( file ) ) msg ("ES2file close:") ; 
  1243.  
  1244.   if ( p == -1 ) {
  1245.     if ( remove ( fname ) )
  1246.       err = msg ( "ES2deleting file %s", fname ) ; 
  1247.     else
  1248.       msg ( "Iremoved %s", fname ) ; 
  1249.   } else {
  1250.     if ( *fname ) msg ( "Ireceived -> %s", fname ) ;
  1251.     sprintf ( fname, "%.*s.%03d", FILENAME_MAX - 5, base, p ) ;
  1252.     if( ( file = fopen ( fname , "rb" ) ) )
  1253.       err = msg ( "E2file (%s) already exists." ) ; 
  1254.     else
  1255.       if ( ( file = fopen ( fname , "wb" ) ) == 0 )
  1256.     err = msg ("ES2opening file\n%s:", fname) ; 
  1257.  
  1258.     if ( ! err ) msg ( "Iopened file %s", fname ) ;
  1259.   }
  1260.   return err ;
  1261. }
  1262.  
  1263.  
  1264. /* Send data for one page. Enable serial port flow control.  Read
  1265.    characters from file and pad lines if necessary.  Bit-reverse characters
  1266.    and escape DLE before storing in buffer.  Flush buffer if enough
  1267.    characters stored.  Append RTC if needed.  Send DLE-ETX and return
  1268.    serial port to command mode when done. Returns 0 if OK, non-0 on
  1269.    errors. */
  1270.  
  1271. int send_data( )
  1272. {
  1273.   int done=0, err=0;
  1274.   int lastc=0, c ;
  1275.   int eol=0, len=0, llen=0, eolcnt=0, rtc=0, skip=0 ;
  1276.   int bytes=0, pad=0, linec=0, lines=0 ;
  1277.   int i, noise=0 ;
  1278.   time_t start, dt ;
  1279.   dtree *t4p = t4tree ;
  1280.  
  1281.   done = err = ttymode ( SEND ) ; 
  1282.   start = time(0) ;
  1283.  
  1284.   while ( ! done ) {
  1285.  
  1286.     if ( ( c = getc ( file ) ) != EOF ) {
  1287.  
  1288. #define T4CODE(l) ( l < 0 ? (eol=l,llen=len,len=0) : (len+=l) ) 
  1289.       T4CTST(c) ;
  1290. #undef T4CODE
  1291.  
  1292.       if ( eol ) {
  1293.     if ( ! llen ) {
  1294.       if ( ++eolcnt >= 6 ) done = rtc = 1 ; 
  1295.     } else {
  1296.       eolcnt=0 ;
  1297.     }
  1298.     if ( eol == -2 ) 
  1299.       msg ("W- image error (line %d)", lines ) ;
  1300.     if ( ! skip ) {
  1301.       lines++ ; 
  1302.       while ( ( linec < minlen || lastc ) ) { 
  1303.         faxputc ( lastc = 0 ) ; 
  1304.         linec++ ; 
  1305.         pad++ ; 
  1306.       }
  1307.       linec = 0 ;
  1308.     }
  1309.     if ( decimate ) {
  1310.       if ( skip ) {
  1311.         skip = 0 ;
  1312.       } else {
  1313.         faxputc ( lastc = 0 ) ; /* force enough zeroes for next EOL */
  1314.         pad++ ; 
  1315.         skip = 1 ;
  1316.       }
  1317.     }
  1318.     if ( faxobytes() > MINWRITE ) { 
  1319.       if ( faxflush() ) done=err=2 ;  
  1320.     }
  1321.     eol=0 ;
  1322.       }
  1323.       if ( ! skip || ! llen ) {
  1324.     faxputc ( lastc = txbitorder [ c ] ) ; 
  1325.     linec ++ ;
  1326.     bytes++ ;
  1327.     if ( lastc == DLE ) { faxputc ( lastc = DLE ) ; linec++ ; pad++ ; }
  1328.       }    
  1329.     } else {
  1330.       done = 1 ;
  1331.       if ( ferror ( file ) ) err = msg ("ES2file read:") ;
  1332.     }
  1333.   }
  1334.  
  1335.   if ( ! err && ! rtc ) {
  1336.     for ( i=0 ; i<T4RTCLEN ; i++ ) faxputdatac ( (T4RTC)[i] ) ;
  1337.     msg ( "I- added RTC (%d bytes)" , T4RTCLEN ) ;
  1338.     pad += T4RTCLEN ;
  1339.   } 
  1340.  
  1341.   for ( ; ( c = faxgetc ( 0 ) ) != EOF ; noise++ ) 
  1342.     msg ( "W-+%s" , cname ( c ) ) ; 
  1343.   if ( noise ) msg ("W- : %d byte(s) received while sending", noise ) ;
  1344.     
  1345.   faxputs ( DLE_ETX ) ;        /* and faxflush() */
  1346.  
  1347.   ckcmd ( &err, 0, TO_DRAIN, OK, 0 ) ;
  1348.  
  1349.   dt = time(0) - start ;
  1350.   msg ("Isent %d lines  %d+%d bytes  %d s  %d bps" , 
  1351.        lines, bytes, pad, (int) dt, ((bytes+pad)*8)/dt ) ;
  1352.  
  1353.   if ( ! err ) err = ttymode ( COMMAND ) ; 
  1354.  
  1355.   return err ;
  1356. }
  1357.  
  1358.  
  1359. /* Receive data. Get characters from the modem and check for
  1360.    errors/EOF.  Remove long runs of zeroes (T.4 FILL). If in DLE
  1361.    escape check for DLE, end of data or protocol violation.
  1362.    Otherwise, test for DLE & write the character out.  Check that
  1363.    the output file is still OK.  If not, send one CANcel
  1364.    character and wait for protocol to complete.  */
  1365.  
  1366. int receive_data ( )
  1367. {
  1368.   int done=0, err=0, nulls=0, c ;
  1369.   int bytes=0, lines=0, nerr=0 ;
  1370.   int eol=0, eolcnt=0, len=0, llen=0, lastlen=0, rtc=0 ;
  1371.   dtree *t4p = t4tree ;
  1372.  
  1373.   while ( ! done ) {
  1374.  
  1375.     if ( ( c = faxgetc( TO_CHAR ) ) == DLE ) {
  1376.       if ( ( c = faxgetc( TO_CHAR ) ) == ETX ) done = 1 ;
  1377.       else if ( c != DLE ) {
  1378.     msg ( "W- \"%s\" received after DLE", cname ( c ) ) ;
  1379.     continue ;
  1380.       }
  1381.     }    
  1382.     if ( c == EOF ) {
  1383.       done = err = msg ("E3fax device read timeout") ;
  1384.       continue ;
  1385.     } 
  1386.     if ( c == 0 ) {
  1387.       if ( ++nulls > MAXNULLS ) {
  1388.     continue ;
  1389.       }
  1390.     } else {
  1391.       nulls = 0 ;
  1392.     }
  1393.     if ( ! done && ! rtc ) {
  1394.       putc ( c = rxbitorder [ c ] , file ) ;
  1395.       bytes++ ;
  1396.     }
  1397. #define T4CODE(l) ( l<0 ? (eol=l, llen=len, len=0) : (len+=l) ) 
  1398.       T4CTST(c) ;
  1399. #undef T4CODE
  1400.     if ( eol ) {
  1401.       lines++ ;
  1402.       if ( ( ( llen != lastlen ) && llen && lastlen && lines > 3 ) ) {
  1403.     nerr++ ;
  1404.     msg ("R-+ (%d:%d)", lines, llen ) ;
  1405.       }
  1406.       lastlen = llen ;
  1407.       if ( ! llen ) {
  1408.     if ( ++eolcnt >= 6 ) rtc = 1 ; 
  1409.       } else {
  1410.     eolcnt=0 ;
  1411.       }
  1412.       eol=0 ; 
  1413.     }
  1414.  
  1415.     if ( ! err && ferror ( file ) ) {
  1416.       err = msg ("ES2fax file write:") ;
  1417.       faxputcnow ( CAN ) ;
  1418.       msg ("Wreceive CANcelled") ;
  1419.     } 
  1420.  
  1421.   } /* while */
  1422.   
  1423.   if ( nerr ) msg ("R-  : reception errors" ) ;
  1424.   nerr /= 2 ;
  1425.   if ( nerr ) msg ("W- %d reception errors", nerr ) ;
  1426.  
  1427.   ckcmd ( &err, 0, TO_C2EOR, ( c1 ? NO : OK ) , 0 ) ;
  1428.   
  1429.   if ( ! err && ! rtc ) {
  1430.     fwrite ( T4RTC , sizeof ( u_char ) , T4RTCLEN , file ) ;
  1431.     msg ( "I- added RTC (%d bytes)" , T4RTCLEN ) ;
  1432.   }
  1433.  
  1434.   msg ( "I- received %d lines, %d bytes, %d errors", lines, bytes, nerr ) ;
  1435.  
  1436.   good = nerr < maxpgerr ;
  1437.   return err ;
  1438. }
  1439.  
  1440.  
  1441. /* Send training check sequence of n zeroes.  Returns 0 or 2 on error. */
  1442.  
  1443. int puttrain ( const char *s , int n )
  1444. {
  1445.   int i, err=0 ;
  1446.  
  1447.   ckcmd ( &err, s , TO_FT , CONNECT, 0 ) ;
  1448.  
  1449.   if ( ! err ) {
  1450.  
  1451.     ttymode ( SEND ) ;
  1452.     for ( i=0 ; ! err && i < n ; i++ ) {
  1453.       faxputc ( 0 ) ;
  1454.       if ( ! ( i & 63 ) ) faxflush ( ) ;
  1455.     }
  1456.     faxputc ( 1 ) ;        /* disable zero-fill padding */
  1457.     faxputs ( DLE_ETX ) ;
  1458.     ttymode ( COMMAND ) ;
  1459.  
  1460.     msg ( "I- sent TCF (%d bytes)", n ) ;
  1461.  
  1462.     ckcmd ( &err, 0, TO_DRAIN, OK, 0 ) ;
  1463.   }
  1464.  
  1465.   return err ;
  1466. }
  1467.  
  1468. /* Checks n bytes of received training check sequence. Skips first n/16
  1469.    bytes.  Returns 0 if OK or ignoring training errors, 1 if too many
  1470.    errors/not enough data, or 3 on other errors. */
  1471.  
  1472. int gettrain ( const char *s , int n ) 
  1473.   int err=0, c, i, errcnt=0, skip=n/16 ;
  1474.  
  1475.   ckcmd ( &err, s , TO_FT , CONNECT, 0 ) ;
  1476.   
  1477.   for ( i=0 ; ! err && ( c = faxgetdatac ( TO_CHAR ) ) >= 0 ; i++ )
  1478.     if ( c != 0 && i >= skip && i < n+skip ) errcnt++ ;
  1479.   
  1480.   ckcmd ( &err, 0, TO_RTCMD, NO, 0 ) ;
  1481.   
  1482.   if ( !err )
  1483.     msg ( "I- received TCF (%s: %d error(s) in %d/%d bytes)", 
  1484.      ( err = i<n || errcnt>MAXTRAINERR ) ? "failed" : "passed" , 
  1485.      errcnt, n, i ) ;
  1486.  
  1487.   return err ;
  1488. }
  1489.  
  1490. /* Log sent/received HDLC frame.  Display of these messages is delayed to
  1491.    avoid possible timing problems. */
  1492.  
  1493. void logfr ( const char *s , const char *nm , u_char *p , int n )
  1494. {
  1495.   int i=0 ;
  1496.   msg ( "I- %s %s", s, nm ) ;
  1497.   msg ( n > 10 ? "H- %s %d bytes:" : "H-+ %s %d bytes:" , s, n ) ;
  1498.   for ( i=0 ; i<n ; i++ ) {
  1499.     msg ( "H-+  %02x" , p[i] & 0xff ) ;
  1500.     if ( ( i&0xf ) == 0xf && i != n-1 ) msg ( "H-" ) ;
  1501.   }
  1502.   msg ( "H-") ;
  1503. }
  1504.  
  1505. /* Send HDLC control frame of type type.  Extra bits are OR'ed to the frame
  1506.    type (FCF) if this frame follows a previous one (no +FTH required) or if
  1507.    more frames will follow.  Sets up flag, address, and fax control field
  1508.    (FCF) bytes in `buf'.  Sends these plus `len` additional bytes.
  1509.    Terminates with DLE-ETX and checks response.  Returns 0 if OK, 2 or 3 on
  1510.    error. */
  1511.  
  1512. #define MORE_FR  0x100 
  1513. #define SUB_FR 0x200 
  1514.  
  1515. int putframe ( int type, u_char *buf , int len )
  1516. {
  1517.   int err=0, i ;
  1518.  
  1519.   buf [ 0 ] = 0xff ;
  1520.   buf [ 1 ] = type & MORE_FR ? 0xc0 : 0xc8 ;
  1521.   buf [ 2 ] = type & 0xff ;
  1522.  
  1523.   if ( ! ( type & SUB_FR ) )
  1524.     ckcmd ( &err, "+FTH=3" , TO_FT, CONNECT, 0 ) ;
  1525.  
  1526.   if ( ! err ) {
  1527.     ttymode ( SEND ) ;
  1528.     for ( i=0 ; ! err && i< len+3 ; i++ )  faxputdatac ( buf [ i ] ) ;
  1529.     faxputs ( DLE_ETX ) ;
  1530.     ttymode ( COMMAND ) ;
  1531.  
  1532.     ckcmd ( &err, 0, TO_DRAIN, type & MORE_FR ? CONNECT : OK , 0 ) ;
  1533.     if ( ! err ) 
  1534.       logfr ( "sent", frname(type & 0x7f), buf, len+3 ) ;
  1535.   }
  1536.  
  1537.   return err ;
  1538. }
  1539.  
  1540.  
  1541. /* Read HDLC frame and store it in buffer buf of size n.  Skips
  1542.    issuing +FRH command on pass==0.  Returns length of frame if
  1543.    OK, EOF on timeout, -3 if any errors as per T.30 5.4.2 (too
  1544.    long, FCS error) */
  1545.  
  1546. int getframe ( int pass , u_char *buf , int n , int t )
  1547. {
  1548.   int err=0, c, i=0 ;
  1549.  
  1550.   if ( pass && ( c = cmd ( "+FRH=3" , t ) ) != CONNECT ) 
  1551.     err = ( c == EOF ) ? -EOF : msg ( "E3get frame command failed") ;
  1552.   
  1553.   if ( err == -EOF ) { faxputc ( CAN ) ; cmd ( "" , TO_ABRT ) ; }
  1554.  
  1555.   if ( ! err ) {
  1556.     for ( i=0 ; ( c = faxgetdatac ( pass ? TO_CHAR : t ) ) >= 0  ; i++ )
  1557.       if ( i < n ) buf[ i ] = c ;
  1558.     if ( c == EOF ) 
  1559.       err = i ? msg ( "E3timed out reading frame data") : EOF ;
  1560.     if ( i >= n ) err = msg ( "E3frame too long (%d bytes)", i ) ;
  1561.   } 
  1562.  
  1563.   ckcmd ( &err, 0, TO_RTCMD, OK, CONNECT ) ;
  1564.  
  1565.   return err ? -err : ( i < n ? i : n ) ;
  1566. }
  1567.  
  1568.  
  1569. /* Reverse bit and byte order of ID strings as per T.30 5.3.6.2.4-6 */
  1570.  
  1571. void revcpy ( u_char *from , u_char *to )
  1572. {
  1573.   int i, j ;
  1574.   for ( i=0, j=IDLEN-1 ; i<IDLEN ; i++, j-- ) 
  1575.     to [ i ] = normalbits [ from [ j ] & 0xff ] ;
  1576. }
  1577.  
  1578.  
  1579. /* Handle procedure interrupt requests (just print message for now).
  1580.    Returns 0. */
  1581.  
  1582. int pr_int( )
  1583. {
  1584.   return msg ("W0procedure interrupt request ignored" ) ;
  1585. }
  1586.  
  1587.  
  1588. /* Class 1 send.  Each received frame elicits an appropriate reply.
  1589.    Optional or unrecognized frames are ignored.  Terminates by sending DCN
  1590.    after receiving MCF after EOP or on error.  Timeouts, bad frames or CRP
  1591.    repeat last command up to MAXRETRY times.  On training check failures
  1592.    the speed (remote capability br) is reduced. The lowest speed is retried
  1593.    MAXTRAIN times.  Page transmission failures are retried NTXRETRY
  1594.    times. */
  1595.  
  1596.  
  1597. enum replies
  1598. { NONE=0x100, DCS1, DCS2, TXDATA, PPM, DONE, BADFR, TIMEOUT, SENDDIS } ;
  1599.  
  1600. int c1send ( int started ) 
  1601.   int err=0, done=0, pass=started, page=1, frame=NONE, reply=DONE ;
  1602.   int frlen, rxdislen=0, disbit=0 ;
  1603.   int cmdtry=0, pagetry=0, traintry=0 ;
  1604.   int ppm=EOP ;
  1605.   u_char buf [ MAXFRLEN ] , *fif=buf+3 ;
  1606.  
  1607.   for ( pass=started ; ! done ; pass++ ) {
  1608.  
  1609.     if ( err ) {
  1610.       frame = NONE ;
  1611.     } else {
  1612.       frlen = getframe ( pass, buf, MAXFRLEN, started ? T3S : T1 ) ;
  1613.       if ( frlen < 3 ) {
  1614.     frame = CRP ;
  1615.       } else {
  1616.     frame = buf [ 2 ] & 0x7f ;
  1617.     logfr ( "received" , frname(frame), buf , frlen ) ;
  1618.     cmdtry = 0 ;
  1619.       }
  1620.     }
  1621.  
  1622.     switch ( frame ) {
  1623.       
  1624.     case CRP:
  1625.       if ( !started || cmdtry++ >= MAXRETRY ) 
  1626.     err = msg ( "E3 no response from remote" ) ;
  1627.       break ;
  1628.  
  1629.     case NSF:
  1630.       reply = NONE ;
  1631.       break ;
  1632.  
  1633.     case CSI:
  1634.       revcpy ( fif , (u_char*) remoteid ) ;
  1635.       msg ( "I- remote ID=\"%*.*s\"" , IDLEN, IDLEN, remoteid ) ;
  1636.       reply = NONE ;
  1637.       break ;
  1638.  
  1639.     case DIS:
  1640.       started = 1 ;
  1641.       disbit = 0x80 ;
  1642.       rxdislen = dislen ( fif ) ;
  1643.       mkcap ( fif , remote , 1 ) ;
  1644.       reply = DCS1 ;
  1645.       break ;
  1646.  
  1647.     case CFR:
  1648.       reply = TXDATA ;
  1649.       break ;
  1650.  
  1651.     case FTT:
  1652.       if ( (remote[BR] = fallback[session[BR]]) > 0 || traintry++ < MAXTRAIN ) 
  1653.     reply = DCS2 ; 
  1654.       else
  1655.     err = msg ( "E1failed to train") ; 
  1656.       break ;
  1657.  
  1658.     case PIP: 
  1659.       pr_int ( ) ; 
  1660.     case RTP:
  1661.     case MCF:
  1662.       page++ ;
  1663.       pagetry=0 ;
  1664.       if ( ppm == MPS && frame == MCF ) reply = TXDATA ;
  1665.       else if ( ppm == EOP ) done = 1 ;
  1666.       else reply = DCS2 ; 
  1667.       break ;
  1668.  
  1669.     case PIN: 
  1670.       pr_int ( ) ;
  1671.     case RTN:
  1672.       if ( pagetry++ < NTXRETRY ) reply = DCS2 ;
  1673.       else err = msg( "E1too many page send retries" ) ;
  1674.       break ;
  1675.  
  1676.     case DCN:
  1677.       err = msg ( "E3remote disconnected") ;
  1678.       break ;
  1679.  
  1680.     case NONE:
  1681.       break ;
  1682.  
  1683.     default:
  1684.       break ;
  1685.  
  1686.     } /* switch ( frame ) */
  1687.  
  1688.     switch ( err || done ? DONE : reply ) {
  1689.  
  1690.     case  DCS1:
  1691.       revcpy ( (u_char*) localid , fif ) ;
  1692.       err = putframe ( TSI + MORE_FR + disbit , buf, IDLEN ) ;      
  1693.                                /* fall through */
  1694.     case DCS2:
  1695.       mincap ( local, remote, session ) ;
  1696.       mkdis ( session , fif , rxdislen , 0 ) ;
  1697.       if ( !err ) err = 
  1698.     putframe ( DCS + (reply==DCS1 ? SUB_FR : 0) + disbit, buf, rxdislen ) ;
  1699.       ckcmd ( &err, "+FTS=8", TO_FT, OK, 0 ) ;
  1700.       if ( !err ) err = 
  1701.     puttrain ( c1cmd [1][1][session[BR]] , 1.65 * cps [ session[BR] ] ) ;
  1702.       reply = DCS2 ;
  1703.       break ;
  1704.  
  1705.     case TXDATA:
  1706.       if ( !err ) err = rdpage ( page, &ppm ) ;
  1707.       ckcmd ( &err,  c1cmd [1][0][session[BR]] , TO_FT, CONNECT, 0 ) ;
  1708.       if ( !err ) err = send_data ( ) ;
  1709.       ckcmd ( &err, "+FTS=8", TO_FT, OK, 0 ) ;      
  1710.                                /* fall through */
  1711.     case  PPM:
  1712.       if ( !err ) err =    putframe ( ppm + disbit, buf, 0 ) ;
  1713.       reply = PPM ;
  1714.       break ;
  1715.  
  1716.     case DONE:
  1717.       putframe ( DCN + disbit, buf, 0 ) ; 
  1718.       done = 1 ;
  1719.       break ;
  1720.  
  1721.     case NONE:
  1722.       break ;
  1723.  
  1724.     default:
  1725.       err = msg ( "E3can't happen(reply)" ) ;
  1726.       break ;
  1727.  
  1728.     } /* switch ( reply ) */
  1729.  
  1730.   } /* for ( ! done ) */
  1731.  
  1732.   return err ;
  1733. }
  1734.  
  1735.  
  1736. /* Class 1 receive.  Sends DIS until gets a DCS or times out.  Sends ppr
  1737.   after ppm and receives data after DCS or MPS. Note: TCF (training check
  1738.   data) is received 75 +/- 20 ms after DCS so there should be no lengthy
  1739.   processing between DCS and gettrain(). */
  1740.  
  1741. int c1receive ( int started ) 
  1742.   int err=0, done=0, page=1, pass, frame, frlen ;
  1743.   u_char buf[MAXFRLEN], *fif=buf+3 ;
  1744.  
  1745.   err = wrpage ( page ) ;
  1746.  
  1747.   for ( pass=started ; ! err && ! done ; pass++ ) {
  1748.  
  1749.     if ( pass > 0 ) {
  1750.       frlen = getframe(pass, buf, MAXFRLEN, started ? T2 : T4 ) ;
  1751.       if ( frlen == EOF ) {
  1752.     frame = started ? TIMEOUT : ( pass < MAXDIS ? SENDDIS : TIMEOUT ) ;
  1753.       } else if ( frlen < 3 ) {
  1754.     frame = started ? NONE : ( pass < MAXDIS ? SENDDIS : NONE ) ;
  1755.       } else {
  1756.     frame = buf [ 2 ] & 0x7f ;
  1757.     logfr ( "received" , frname(frame), buf , frlen ) ;
  1758.       }
  1759.     } else {
  1760.       frame=SENDDIS ;
  1761.     }
  1762.  
  1763.     switch ( frame ) {
  1764.       
  1765.     case SENDDIS:
  1766.       revcpy ( (u_char*) localid, fif ) ;
  1767.       if ( !err ) err = 
  1768.     putframe ( CSI + MORE_FR + ( pass ? 0 : SUB_FR ), buf, IDLEN ) ;
  1769.       mkdis ( local , fif , DEFDISLEN , 1 ) ;
  1770.       if ( !err ) err = 
  1771.     putframe ( DIS + SUB_FR , buf, DEFDISLEN ) ;
  1772.       break ;
  1773.       
  1774.     case TIMEOUT:
  1775.       done = err = msg ( "E3timed out waiting for sender" ) ;
  1776.       break; 
  1777.  
  1778.     case BADFR :
  1779.       msg ( "W bad frame" ) ;
  1780.       break ;
  1781.  
  1782.     case TSI: ;
  1783.       revcpy ( fif , (u_char*) remoteid ) ;
  1784.       msg ( "I- remote ID=\"%*.*s\"" , IDLEN, IDLEN, remoteid ) ;
  1785.       break ;
  1786.       
  1787.     case DCS: ;
  1788.       started = 1 ;
  1789.       mkcap ( fif , session  , 0 ) ;
  1790.       printcap ( "session" , session ) ;
  1791.       if ( gettrain ( c1cmd [0][1][session[BR]], cps[session[BR]] ) == 0 ) {
  1792.     if ( !err ) err = putframe ( CFR, buf, 0 ) ;
  1793.     if ( !err ) goto getdata ;
  1794.       } else {
  1795.     if ( !err ) err = putframe ( FTT, buf, 0 ) ;
  1796.       }
  1797.       break ;
  1798.  
  1799.     case PRI_EOM:
  1800.     case PRI_MPS:
  1801.     case PRI_EOP:
  1802.       pr_int() ;
  1803.  
  1804.     case EOM:
  1805.     case MPS:
  1806.     case EOP:
  1807.       err = wrpage ( ++page ) ;    
  1808.       if ( ! err )
  1809.     if ( good ) err = putframe ( MCF, buf, 0 ) ;
  1810.     else        err = putframe ( RTN, buf, 0 ) ;
  1811.       if ( ! err && good && ( frame == MPS || frame == PRI_MPS ) )
  1812.     goto getdata ; 
  1813.       if ( ! err && good && ( frame == EOM || frame == PRI_EOM ) ) {
  1814.     pass=0 ;
  1815.     ckcmd ( &err, "+FTS=8", TO_FT, OK, 0 ) ;      
  1816.       }
  1817.       break ;
  1818.  
  1819.     getdata:
  1820.       ckcmd ( &err, c1cmd [0][0][session[BR]] , TO_FT, CONNECT, 0 ) ;
  1821.       if ( !err ) err = receive_data (  ) ;
  1822.       break ;
  1823.       
  1824.     case DCN:
  1825.       done = 1 ;
  1826.       break;
  1827.  
  1828.     } /* switch */
  1829.     
  1830.   } /* do */
  1831.  
  1832.   wrpage ( -1 ) ;        /* remove last file */
  1833.   return err ;
  1834. }
  1835.  
  1836. /* Class 2 fax transmission.  Retries each page up to NTXRETRY times.
  1837.    Transmission begins after DC2 or XON is received.  Sends the data and
  1838.    sends appropriate post-page message.  Checks for 'good' status set in
  1839.    cmd() by +FPTS: responses. */
  1840.  
  1841. int c2send ( )
  1842. {
  1843.   int c, page, err=0, done=0, try, ppm=0, noise=0 ;
  1844.  
  1845.   for ( page=1 ; !err && ! done ; page++ ) {
  1846.  
  1847.     for ( try=good=0 ; !err && !good && try<NTXRETRY ; try++ ) {
  1848.  
  1849.       err = rdpage ( page , &ppm ) ;
  1850.  
  1851.       ckcmd ( &err, "+FDT" , TO_C2B , CONNECT, 0 ) ;
  1852.   
  1853.       if ( ! err ) 
  1854.     while ( !err && ( c = faxgetc ( TO_C2X ) ) != XON && c != DC2 )
  1855.       if ( c == EOF ) {
  1856.         msg ( "Wno XON/DC2 received after CONNECT") ;
  1857.         break ;
  1858.       } else { 
  1859.         msg ( "W+%s", cname ( c ) ) ; 
  1860.         noise++ ; 
  1861.       }
  1862.  
  1863.       if ( noise ) {
  1864.     msg ( "Wreceived (%d) characters while waiting to send", noise ) ;
  1865.     noise = 0 ;
  1866.       }
  1867.  
  1868.       if ( ! err ) err = send_data ( ) ;
  1869.  
  1870.       good = 1 ; /* assume good if no +FPTS: */
  1871.       ckcmd ( &err, ppm == EOP ? "+FET=2" : "+FET=0" , TO_C2PP, OK, 0 ) ;
  1872.  
  1873.       if ( hsc > 0 ) err = msg ( "E2abnormal termination (code %d)", hsc ) ;
  1874.     }
  1875.     if ( ppm == EOP ) done = 1 ;
  1876.     if ( try >= NTXRETRY ) {
  1877.       err = msg ( "E2too many page send retries" ) ;
  1878.       cmd ( "+FK", T3S ) ;
  1879.     }
  1880.   } 
  1881.   return err ; 
  1882. }
  1883.  
  1884. /* Class 2 fax reception.  Send fax data receive command.  If
  1885.    response is OK, then no more pages are coming.  If it's
  1886.    CONNECT receive the data for one page.  Returns 0 or >= 2 for
  1887.    errors.  */
  1888.  
  1889. int c2receive ( )
  1890. {
  1891.   int err=0, page=1, done=0, c ;
  1892.  
  1893.   err = wrpage ( page ) ;
  1894.  
  1895.   while ( ! err && ! done && hsc < 0 ) {
  1896.     if ( ( c = cmd ( "+FDR" , TO_C2R ) ) == CONNECT ) {
  1897.       faxputcnow ( startchar ) ;
  1898.       err = receive_data ( ) ;
  1899.       ckcmd ( &err, good ? "+FPTS=1" : "+FPTS=2", T3S , OK, 0 ) ;
  1900.       if ( ! err ) err = wrpage ( ++page ) ;
  1901.     } else {
  1902.       if ( c == OK ) { wrpage ( -1 ) ; done = 1 ; } 
  1903.       else err = msg ( "E3receive (+FDR) command failed") ;
  1904.     }
  1905.   } 
  1906.   if ( hsc > 0 ) err = msg ( "E2abnormal call termination (code %d)", hsc ) ;
  1907.   
  1908.   return err ;
  1909. }
  1910.  
  1911. /* Dial a number and send a fax. */
  1912.  
  1913. int send ( char *tel , char *faxfile )
  1914. {
  1915.   char c, s [ 128 ] ;
  1916.   int err=0 ;
  1917.  
  1918.   msg ( "Idialing %.127s", tel ) ;
  1919.   sprintf ( s , "D%.127s" , tel ) ;
  1920.  
  1921.   err = begin_session ( faxfile ) ;
  1922.  
  1923.   if ( ! err ) {
  1924.     if ( ( ( c = cmd ( s , TO_A ) ) == ( c1 ? CONNECT : OK ) ) && hsc < 0 ) 
  1925.       msg ( "Iconnected" ) ; 
  1926.     else if ( c ==  BUSY ) 
  1927.       err = msg ( "W1number is busy" ) ; 
  1928.     else 
  1929.       err = msg ( "E2can't establish session" ) ;
  1930.  
  1931.     if ( ! err ) 
  1932.       err = c1 ? c1send ( 0 ) : c2send ( ) ;
  1933.  
  1934.     if ( err != 1 && err < 4 ) end_session( ) ;
  1935.   }
  1936.  
  1937.   return err ;
  1938. }
  1939.  
  1940.  
  1941. /* Receive a fax.  Open modem device and initialize it.  Remove locks if
  1942.    sharing device with outgoing calls.  If waiting for call, wait for modem
  1943.    activity, else answer phone.  Figure out what mode we answered in and
  1944.    handle call appropriately.  Re-lock if necessary. Then exec *getty or
  1945.    run class 1 or class 2 reception routines. Modems prompt as follows
  1946.    after answering: Class 0: CONNECT nnn for data; Class 1: FAX + CONNECT
  1947.    for fax, DATA + CONNECT nnn for data, just CONNECT for fax if +FAE=0;
  1948.    Class 2: CONNECT (data) or OK (fax). ("+FCON" and "CONNECT FAX" are 
  1949.    status messages, not prompts). */
  1950.  
  1951. int receive ( char *faxfile )
  1952. {
  1953.   enum connectmode { NONE, DATAMODE, FAXMODE } ; 
  1954.   enum connectmode mode=NONE ;
  1955.   int c=0, err ;
  1956.  
  1957.   if ( ( err = begin_session ( faxfile ) ) == 0 ) {
  1958.  
  1959.     if ( ! err && share ) err = unlockall ( ) ;
  1960.  
  1961.     if ( ! err && waitforcall ) {
  1962.       msg ( "Iwaiting for activity on %s", faxfile ) ;
  1963.       faxdata ( -1 ) ;
  1964.       msg ( "Iactivity detected at ") ;
  1965.     }
  1966.   
  1967.     if ( ! err && share ) {
  1968.       msleep ( 200 ) ;        /* let other programs lock port  */
  1969.       err = lockall ( ) ;
  1970.     }
  1971.  
  1972.     if ( ! err && softadans && *getty ) {
  1973.       if ( cmd ( ( waitforcall ? 0 : "A" ) , TO_DATAF ) == CONNECT ) 
  1974.     mode = DATAMODE ;
  1975.       else {
  1976.     int i ; /* abort data answer mode & set fax mode to try again */
  1977.     for ( i=0 ; i<3 ; i++ ) 
  1978.       if ( cmd ( c1 ? "+FCLASS=1" : "+FCLASS=2" , -TO_RESET ) == OK )
  1979.         break ; 
  1980.       }
  1981.     }
  1982.     if ( ! err && mode == NONE ) {
  1983.       c = cmd ( ! waitforcall || ( softadans && *getty ) ? "A" : 0 , TO_A ) ;
  1984.       if ( c1 )
  1985.     mode = ( c == CONNECT ) ? ( datamode ? DATAMODE : FAXMODE ) : NONE ;
  1986.       else
  1987.     mode = ( c == CONNECT ) ? DATAMODE : ( c == OK ? FAXMODE : NONE ) ;
  1988.     }
  1989.     
  1990.     if ( err || hsc >= 0 ) mode = NONE ;
  1991.  
  1992.     if ( ! err )
  1993.       switch ( mode ) {
  1994.       case DATAMODE : {
  1995.         char buf [ MAXGETTY ] ;
  1996.     msg ( "Idata call answered") ;
  1997.     sprintf ( buf , getty , crate, crate, crate, crate, crate, crate ) ;
  1998.     msg ( "Iexec'ing /bin/sh -c \"%s\"" , buf ) ;
  1999.     execl ( "/bin/sh" , "sh" , "-c" , buf , (void*) 0 ) ; 
  2000.     err = msg ( "ES2exec failed:" ) ;
  2001.     break ; }
  2002.       case FAXMODE :
  2003.     msg ( "Ifax call answered") ;
  2004.     break ;
  2005.       case NONE:
  2006.     err = msg ( "E3unable to answer call") ;
  2007.     break ;
  2008.       }
  2009.     
  2010.     if ( ! err ) err = c1 ? c1receive ( 0 ) : c2receive ( ) ;
  2011.     
  2012.     if ( err != 1 && err < 4 ) end_session( ) ;   /* if not locked */
  2013.   }
  2014.   
  2015.   return err  ;
  2016. }
  2017.  
  2018.  
  2019. /* Simple (one option per argument) version of getopt(3). */
  2020.  
  2021. int optind = 1 ;
  2022. char *optarg ;
  2023.  
  2024. int nextopt( int argc, char **argv, char *args )
  2025. {
  2026.   char *a, *p ;
  2027.  
  2028.   if ( optind >= argc || *(a = argv[optind]) != '-' ) return -1 ;
  2029.   optind++ ;
  2030.  
  2031.   if ( ! *(a+1) || ! ( p = strchr ( args , *(a+1) ) ) )
  2032.     return msg ( "Eunknown option (%s)" , a ) , '?' ; 
  2033.  
  2034.   if ( *(p+1) != ':' ) optarg = 0 ;
  2035.   else
  2036.     if ( *(a+2) ) optarg = a+2 ;
  2037.     else
  2038.       if ( optind >= argc ) return msg ( "Eno argument for (%s)", a ) , '?' ;
  2039.       else optarg = argv [ optind++ ] ;
  2040.   return *(a+1) ;
  2041. }
  2042.  
  2043.  
  2044. /* Fax send/receive program for Class 1 or 2 fax modems. Initialize
  2045.    character name, bit reversal and T.4 decoding tables and process
  2046.    arguments.  Returns 0 on success, 1 if number busy or device locked, 2
  2047.    for errors, 3 for protocol errors, 4 if no modem response, 5 on fatal
  2048.    signal. */
  2049.  
  2050. int main( int argc, char **argv)
  2051. {
  2052.   int i, err=0 , c, nlocks=0 ;
  2053.   char *faxfile = FAXFILE ;
  2054.   char capinit [ CMDBUFSIZE ] , idinit [ CMDBUFSIZE ] ;
  2055.   char msgbuf [ MAXMSGBUF ] ;
  2056.  
  2057.   argv0 = argv[0] ;
  2058.  
  2059.   setvbuf ( LOGF , msgbuf , _IOFBF , MAXMSGBUF ) ;
  2060.  
  2061.   msg ( "I " Version "  starts ") ;
  2062.   msg ( "I " Copyright "  (compiled "__DATE__ " " __TIME__ ")" ) ;
  2063.  
  2064.   argv0 = strrchr ( argv0 , '/' )  ;
  2065.   if ( ! argv0 ) argv0 = argv[0] ; else argv0++ ;
  2066.  
  2067.   cname ( 0 ) ;
  2068.   for ( i=0 ; i<256 ; i++ ) normalbits [ reversebits [ i ] = i ] = 
  2069.     ( i& 1 ? 128:0 ) | ( i& 2 ? 64:0 ) | ( i& 4 ? 32:0 ) | ( i&  8 ? 16:0 ) |
  2070.     ( i&16 ?   8:0 ) | ( i&32 ?  4:0 ) | ( i&64 ?  2:0 ) | ( i&128 ?  1:0 ) ;
  2071.   t4tree = unpktree( ) ;
  2072.   
  2073.   while (!err && (c=nextopt(argc,argv,"c:d:g:i:l:o:q:r:st:v:wx:z:T") ) != -1) {
  2074.     switch (c) {
  2075.     case 'c': 
  2076.       err = str2cap ( optarg , local ) ;
  2077.       sprintf ( capinit , "+FDCC=%.*s" , CMDBUFSIZE-7, optarg ) ;
  2078.       if ( !err && !c1 ) { optarg = capinit ; goto addopt ; }
  2079.       break ;
  2080.     case 'l': 
  2081.       if ( strlen ( optarg ) > IDLEN ) 
  2082.     msg("Wlocal ID (%s) truncated to 20 characters", optarg ) ;
  2083.       if ( strspn ( optarg, " +0123456789" ) != strlen ( optarg ) )
  2084.     msg("Wlocal ID (%s) has non-standard characters", optarg ) ;
  2085.       sprintf ( localid, "%*.*s", IDLEN, IDLEN, optarg ) ;
  2086.       sprintf ( idinit , "+FLID=\"%.*s\"" , CMDBUFSIZE-9, localid ) ;
  2087.       if ( !c1 ) { optarg = idinit ; goto addopt ; }
  2088.       break ;
  2089.     case 'i': 
  2090.     addopt:
  2091.       if ( niopt < MAXIOPT ) iopt [ niopt++ ] = optarg ;
  2092.       else err = msg ( "E2too many modem init commands"); 
  2093.       break ;
  2094.     case 'z': 
  2095.       if ( nzopt < MAXIOPT ) zopt [ nzopt++ ] = optarg ;
  2096.       else err = msg ( "E2too many modem reset commands"); 
  2097.       break ;
  2098.     case 'd': faxfile = optarg ; break ;
  2099.     case 'g': getty = optarg ; break ;
  2100.     case 'o': 
  2101.       for ( ; *optarg ; optarg++ ) 
  2102.     switch ( *optarg ) {
  2103.     case '1' : c1 = 1 ; break ;
  2104.     case 'a' : softadans = 1 ;  break ;
  2105.     case 'e' : igniniterr = igniniterr ? 0 : 1 ;  break ;
  2106.     case 'r' : rxbitorder = reversebits ; break ;
  2107.     case 'x' : startchar = XON ; break ;
  2108.     case 'z' : cmdpause += T_CMD ; break ;
  2109.      default : msg ( "Wunrecognized protocol option (%c)", *optarg ) ; 
  2110.     }
  2111.       break ;
  2112.     case 'q':
  2113.       if ( sscanf ( optarg , "%d", &maxpgerr ) != 1 )
  2114.     err=msg ("E2can't read quality (-q) argument (%s)", optarg ) ;
  2115.       break;
  2116.     case 'r': 
  2117.       fnamepat = optarg ;
  2118.       err = receive ( faxfile ) ; 
  2119.       break;
  2120.     case 's': share = 1 ; break;
  2121.     case 't': 
  2122.       fnames = argv + optind ;
  2123.       nfiles = argc - optind ;
  2124.       err = send ( optarg , faxfile ) ; 
  2125.       break;
  2126.     case 'v': 
  2127.       verb = optarg ;
  2128.       if ( strchr ( verb , 'a' ) )
  2129.       for ( i=0 ; i<argc ; i++ ) msg ( "Iargv[%d]=%s", i, argv[i]) ; 
  2130.       break ;
  2131.     case 'w': waitforcall = 1 ; break ;
  2132.     case 'x': 
  2133.       if ( nlocks < MAXLKFILE ) lkfiles [ nlocks++ ] = optarg ; 
  2134.       else err = msg ( "E2too many lock files" ) ; 
  2135.       break ;
  2136.     case 'T':            /* test: begin+end session */
  2137.       if ( ( err = begin_session ( faxfile ) ) == 0 ) end_session( ) ;
  2138.       break ;
  2139.     default : fprintf ( stderr, Usage, argv0 ) ; err = 2 ; break ;
  2140.     }
  2141.   }
  2142.  
  2143.   msg ( "Idone, returning %d", err ) ;
  2144.   return err ;
  2145. }
  2146.